JUC

 

 java内存模型决定一个线程对共享变量的写入何时对另一个线程可见。从抽样的角度来说:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。

                1, 存在两种内存:主内存和线程本地内存,线程开始时,会复制一份共享变量的副本放在本地内存中。
                2, 线程对共享变量操作其实都是操作线程本地内存中的副本变量,当副本变量发生改变时,线程会将它刷新到主内存中(并不一定立即刷新,何时刷新由线程自己控制)。
                3 ,当主内存中变量发生改变,就会通知发出信号通知其他线程将该变量的缓存行置为无效状态,因此当其他线程从本地内存读取这个变量时,发现这个变量已经无效了,那么它就会从内存重新读取。

JMM要求:1,可见性;2,原子性;3,有序性

 

 多线程操作共享变量,会产生上面三个问题,可见性、有序性和原子性。

  1. 可见性: 一个线程改变共享变量,可能并没有立即刷新到主内存,这个时候另一个线程读取共享变量,就是改变之前的值。所以这个共享变量的改变对其他线程并不是可见的。
  2. 有序性: 编译器和处理器会对指令进行重排序,语句的顺序发生改变,这样在多线程的情况下,可能出现奇怪的异常。
  3. 原子性: 只有对基本数据类型的变量的读取和赋值操作是原子性操作。

 

要解决这三个问题有两种方式:

  方法一,volatile关键字(轻量锁):它只能解决两个问题可见性和有序性问题,但是如果volatile修饰基本数据类型变量,而且这个变量只做读取和赋值操作,那么也没有原子性问题了。比如说用它来修饰boolean的变量。

      解决办法: CAS(Compare and Swap)即比较并交换:

                                        底层依赖unsafe类,会引入ABA问题,如何规避ABA问题?

         方法二,加锁(悲观锁):可以保证同一时间只有同一线程操作共享变量,当前线程操作共享变量时,共享变量不会被别的线程修改,所以可见性、有序性和原子性问题都得到解决。分为synchronized同步锁和JUC框架下的Lock锁。

         

 

posted @ 2020-08-04 09:11  NangKe  阅读(315)  评论(0编辑  收藏  举报