1.为什么引入线程同步
多个线程对同一个值进行修改,由于线程在会将值放在cache进行缓存,因此各个线程修改各自的缓存值,最终导致线程对值的修改对其他线程不可见,进而引发逻辑问题
2.volatile内存可见 原子性 有序性 以及禁止指令重排他们的意义是什么,这个关键字线程安全吗?
在问题1里面概述了线程不同步的原因,接下来讲讲java是怎么解决的。
那就是volatile关键字 线程修改变量,变量将值刷入主存,后续其他线程读变量时候则不是从缓存读取,而是从主存读取
禁止指令重排也是为了保证可见性
3.ConcurrentHashMap原理是怎么实现线程安全的
在这之前需要讲一下cas是怎么实现线程安全的
cas:swap and compare
预期三个值 当前内存值V 本地旧的值A 新来的要修改的值B
如果V==A, 那么将B赋值给V
否则,不执行赋值操作
为什么这么搞实现了线程安全呢,变量存储在线程缓存中,假如主存数据被修改,那么线程缓存的旧值和新值就不一致了,此时不应该执行set操作了,此时需要更新缓存值
讲清楚cas线程安全原理,此时可以将concurrenthashmap的原理了
很简单,hashmap的结构是数组加链表的结构,如果对整个map加锁的话,那么此时就是hashtable了
如果对map中每个数组元素进行加锁的话,这就是1.7的实现了,也就是分段锁
如果在put时对数组元素进行cas操作,对链表或者红黑树加锁的话,那就是1.8的实现了。
由于每个元素都枷锁,所以对于1.7版本来说的话,它这个所加的是node,也就是数组元素,数组长度就那点,所以能够同时写的线程数量是和数组长度一致的,因此1.7废弃了segment的实现
但是,从1.7的实现和hashtable进行比对就可以发现,锁优化本质上就是一个将锁的粒度变得越来越细的一个过程,如果足够细,细到原子级别,那就直接就成了cas了,锁的问题基本就没了