其他分享
首页 > 其他分享> > JUCJUC

JUCJUC

作者:互联网

1.volatile

//轻量级的JAVA同步机制
特点1:保证内存可见性
对于普通的变量,线程A将其修改为某个值发生在线程A的本地内存中,此时还未同步到主内存中去;而线程B已经缓存了该变量的旧值,所以就导致了共享变量值得不一致。解决这种共享变量在多线程模型中的不可见性问题,比较粗暴的方式是加锁,但是太重量级,所以用volatile比较合理。
方式:(1)他会强制将对共享变量的修改操作立即写入主内存。
(2)如果是写操作,他会导致其他线程中的对应的缓存无效,所以其他线程用到该变量时,必须从主内存重新获取。
JAVA内存模型:由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方成为栈空间),工作内存是每个线程的私有数据区域,而Java内存模型中规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可访问,但线程对变量的操作(读取赋值等)必须在工作内存中进行,首先要将变量从主内存拷贝到自己的工作空间,然后对变量进行操作,操作完成再将变量写回主内存,不能直接操作主内存中的变量,各个线程中的工作内存储存着主内存中的变量副本拷贝,因此不同的线程无法访问对方的工作内存,此案成间的通讯(传值) 必须通过主内存来完成
内存可见性:一个线程对共享变量的修改,能够及时的被其他线程看到
特点二:禁止指令重排
方式:内存屏障
写操作时:
在这里插入图片描述
读操作时:
在这里插入图片描述
特点3:不保证原子性
多个线程对同一个变量进行+1操作时,预期值达不到。
线程A从内存中拿到变量值1,然后线程A被阻塞,此时线程B也拿到变量值,由于没有被修改,所以线程B拿到的值也为1,进行+1操作,此时变量的值为2,此时A线程被唤醒,由于A线程已经读取过变量的值,所以继续在1的基础上进行+1操作。这样就会出问题。

2.AtomicInteger

可以解决volatile的原子性问题。
方式:CAS CompareAndSwap 比较并操作 unsafe类的native方法
下图是AtomicInteger的自增方法
传入三个参数,第一个是当前对象,第二个是内存地址偏移,第三个是+1
通过当前对象和内存地址偏移可以获得当前的值(var5),然后调用compareAndSwapInt方法,如果通过当前变量和地址偏移获取的值和var5(上面获取的)的值一致,就进行+1操作(var4的值为1),并返回true,取反返回false,退出循环,返回+1后的var5的值。
在这里插入图片描述
这里如果两个线程同时操作一个变量进行++操作,A线程拿到值1后阻塞,B线程也拿到值1进行+1操作,值变为2,此时A线程被唤醒,执行+1操作,此时A拿的值为1,但是compareAndSwapInt时发现从通过当前变量和地址偏移拿到的值为2,就不进行+1操作,必须再执行一次do中的操作,拿到最新的值,此时才能执行+1的操作。保证了原子性。

标签:变量,拿到,线程,内存,JUCJUC,操作,偏移
来源: https://blog.csdn.net/weixin_46666822/article/details/121443969