找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1922923|回复: 0

浅谈synchronized和volatitle实现线程安全的策略

[复制链接]

该用户从未签到

发表于 2021-5-1 19:16:20 | 显示全部楼层 |阅读模式

您需要 登录 才可以下载或查看,没有账号?立即注册

×
我对线程安全的理解就是多个线程同时操作一个共享变量时会产生意料之外的情况,这种情况就是线程不安全。注意:只有写操作才可能出现线程不安全,对共享变量只进行读操作线程是绝对安全的。
具体线程不安全的例子有一个很经典的就是两个线程都对一个共享变量x=0执行100次自增操作,但是x的结果并非200
你可能会好奇线程是如何获取共享变量的,这就为你解答
Java线程之间的通信由Java内存模型(简称JMM)控制,从抽象的角度来说,JMM定义了线程和主内存之间的抽象关系。JMM的抽象示意图如图所示:

                               
登录/注册后可看大图

从图中我们可以看到:
[list,
[*,共享变量存在于主内存中,也就是堆内存
[*,每一个线程都保存了一份该线程使用到的共享变量的副本
[*,线程读取共享变量优先从本地内存(也就是栈内存)中读取,写共享变量先写到栈内存,再写入堆内存
[*,线程之间对共享变量的通信只能通过堆内存
[/list,以上只是Java内存模型的抽象图,实际上线程的工作模型是这样的,栈内存即是两个缓冲区

                               
登录/注册后可看大图

接下来看一个线程不安全的例子:
假设线程A、B操作同一个共享变量X,初始两级Cache都为空
[list=1,
[*,线程A想要读取X的值,由于两级Cache都没有命中,因此加载堆内存中的X=0,并缓存到两个Cache中
[*,线程A修改X的值为1,为为两个Cache刷新X,再刷新到堆内存
[*,线程B想要获取X的值,一级缓存没有获取到,二级缓存命中,读取到X=1
[*,线程B想要修改X的值为2,先刷新自,己的一级缓存为2,再刷新二级缓存和堆内存中的X为2。目前为止一切正常,接下来重点来了
[*,线程A想要读取X的值,一级缓存命中此时X=1,但是堆内存中的X=2。可以看到线程B写入的共享变量对X不可见,出现了线程不安全的情况。
[/list,由于Java内存机制就是这样设计的,因此多个线程操作同一个变量会产生不安全的问题,volatitle关键字这是被设计出来解决这一问题的,它只能用于单个变量
还是接着上面这个例子,我们这样定义X
volatle int X=0
volatile的内存语义是:
当一个线程对volatile修饰的变量进行写操作时,JMM会立即将该线程对应的栈内存中的副本的值刷新到堆内存中;当一个线程对volatile修饰的变量进行读时,JMM会清空此变量的一二级缓存,直接从堆内存中读取共享变量的值。
volatile可以当作一个轻量级的锁来使用,但volatile仅仅只能保证共享变量内存的可见性,不能保证操作共享变量的原子性,而锁(如synchronized)能保证整段锁范围内的代码具有原子性。
首先要明确的是synchronized不是锁,锁都是基于对象的(Object的子类),Java中的每一个对象都可以作为一个锁。
synchronized是Java的一个关键字,保证临界区内的代码同一时刻只能有一个线程执行。
线程的执行代码在进入synchronized代码块前会自动获取内部锁,这时候其他线程访问该同步代码块时会被阻塞挂起。拿到内部锁的线程会在正常退出同步代码块或者抛出异常后或者在同步块内调用了该内置锁资源的wait系列方法时释放该内置锁。内置锁是排它锁,也就是当一个线程获取这个锁后,其他线程必须等待该线程释放锁后才能获取该锁。
[indent,sysnchronized的内部锁可以是:
当前类的class字节码对象:this.getClass
当前类的一个实例:this
一个Object对象
wait和notify方法只能用于synchronized同步代码块内
[/indent,与volatile不同
进入synchronized块的内存语义是把再synchronized块内使用到的所有共享变量从栈内存中清空,这样就只能从堆内存只读取,保证了内存可见性。退出synchronized块的内存语义是把synchronized块内对共享变量的修改刷新到堆内存。
仔细想想,这其实也是一个加锁和解锁的过程,保证共享变量修改的可见性。
回复

使用道具 举报

网站地图|页面地图|文字地图|Archiver|手机版|小黑屋|找资源 |网站地图

GMT+8, 2024-6-2 17:08

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表