并发程序正确地执行,必须要保证原子性、可见性以及有序性。只要有一个没有被保证,就有可能会导致程序运行不正确。
原子性:表示这个线程是不可分割的.中间没办法被其他线程打断
可见性:表示这个线程执行之后的结果能马上被其他线程知道
有序性:表示这个线程的执行是有顺序的
volatile关键字来保证可见性。
volatile关键字保证了操作的可见性,但是volatile不能保证对变量的操作是原子性
volatile能在一定程度上保证有序性
观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令”
lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:
1)它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
2)它会强制将对缓存的修改操作立即写入主存;
3)如果是写操作,它会导致其他CPU中对应的缓存行无效
1)正如我所说,HashMap和ConcurrentHashMap之前的第一个显着区别是后来是线程安全的,可以在没有外部同步的并发环境中使用。虽然它没有提供与使用Hashtable相同的同步级别,但它足以实现最实用的目的。
2)你可以通过将它包装在Collections.synchornizedMap(HashMap)上来使HashMap同步,它将返回一个几乎等同于Hashtable的集合,其中Map上的每个修改操作都被锁定在Map对象上,而在ConcurrentHashMap的情况下,线程安全是通过将整个Map划分为基于并发级别的不同分区并且仅锁定特定部分而不是锁定整个Map来实现的。
3)ConcurrentHashMap比多线程环境中的Synchronized HashMap更具可伸缩性和性能,而在单线程环境中,HashMap和ConcurrentHashMap都提供了相当的性能,其中HashMap稍微好一些。
ConcurrentHashMap 类中包含两个静态内部类 HashEntry 和 Segment。HashEntry 用来封装映射表的键 / 值对;Segment 用来充当锁的角色,每个 Segment 对象守护整个散列映射表的若干个桶。每个桶是由若干个 HashEntry 对象链接起来的链表。一个 ConcurrentHashMap 实例中包含由若干个 Segment 对象组成的数组。
ConcurrentHashMap:https://www.ibm.com/developerworks/cn/java/java-lo-concurrenthashmap/index.html
内置锁的重入:等于是一个线程获取到一个锁的时候,可以再次获取同一个锁,这个叫重进入,当然在退出的时候也是按顺序解锁
threadLocal:相当于一个共享的全局变量,可以把线程相对应的数据存进去,然后再需要的时候取出来,
如何保证对象不可变
网友评论