栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

Javaatomic / volatile / synchronized有什么区别?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Javaatomic / volatile / synchronized有什么区别?

你是在专门询问它们在内部如何工作,所以你在这里:

No synchronization

private int counter;public int getNextUniqueIndex() {  return counter++; }

它基本上是从内存中读取值,然后将其递增并放回内存中。它可以在单线程中运行,但在当今的多核,多CPU,多级缓存时代,它无法正常工作。首先,它引入了竞争条件(多个线程可以同时读取值),还引入了可见性问题。该值可能仅存储在“ 本地 ” CPU内存(某些缓存)中,而其他CPU /内核(因此-线程)不可见。这就是为什么许多人在线程中引用变量的本地副本的原因。这是非常不安全的。考虑以下流行但破损的线程停止代码:

private boolean stopped;public void run() {    while(!stopped) {        //do some work    }}public void pleaseStop() {    stopped = true;}

添加

volatile
stopped
变量,它可以正常工作-如果任何其他线程stopped通过pleaseStop()方法修改了变量,则可以保证在工作线程的while(!stopped)循环中立即看到该更改。顺便说一句,这也不是中断线程的好方法,请参阅:如何停止永远不运行的线程以及停止特定的Java线程。

AtomicInteger

private AtomicInteger counter = new AtomicInteger();public int getNextUniqueIndex() {  return counter.getAndIncrement();}

AtomicInteger
类使用CAS(比较并交换)低级别的CPU操作(没有同步需要!)他们允许你修改某个变量只有当现值等于其他的东西(并成功返回)。因此,当你执行
getAndIncrement()
它时,它实际上是在循环中运行(简化的实际实现):

int current;do {  current = get();} while(!compareAndSet(current, current + 1));

所以基本上:阅读;尝试存储增加的值;如果不成功(该值不再等于current),请阅读并重试。的compareAndSet()是在本机代码(组件)来实现。

volatile without synchronization

private volatile int counter;public int getNextUniqueIndex() {  return counter++; }

该代码不正确。它解决了可见性问题(volatile确保其他线程可以看到对所做的更改counter),但仍然存在竞争状况。这已被多次解释:递增前/递后不是原子的。

唯一的副作用

volatile
是“ 刷新 ”缓存,以便所有其他方都能看到最新版本的数据。在大多数情况下,这太严格了;这就是为什么
volatile
不是默认值。

volatile without synchronization (2)

volatile int i = 0;void incIBy5() {  i += 5;}

与上述相同的问题,但更糟糕的i是,不是private。竞赛条件仍然存在。为什么会出问题呢?例如,如果两个线程同时运行此代码,则输出可能为+ 5或+ 10。但是,你一定可以看到更改。

Multiple independent synchronized

void incIBy5() {  int temp;  synchronized(i) { temp = i }  synchronized(i) { i = temp + 5 }}

令人惊讶的是,此代码也不正确。实际上,这是完全错误的。首先,你要在上进行同步i,该操作将被更改(此外,i它是原始操作,因此我想你正在Integer通过自动装箱创建的临时文件上进行同步…)完全有缺陷。你还可以编写:

synchronized(new Object()) {  //thread-safe, SRSLy?}

没有两个线程可以使用相同的锁进入同

synchronized
一块。在这种情况下(以及类似地在你的代码中),锁定对象在每次执行时都会更改,因此实际上无效。
synchronized

即使你使用了最终变量(或

this
)进行同步,代码仍然不正确。两个线程可首先读取i到temp同步(具有相同值的局部地
temp
),则第一分配一个新的值
i
(比如说,从1到6)和所述另一种做同样的事情(从1到6)。

同步必须从读取到分配值。你的第一次同步无效(读取int是原子的),而第二次同步也无效。我认为这些是正确的形式:

void synchronized incIBy5() {  i += 5 }void incIBy5() {  synchronized(this) {    i += 5   }}void incIBy5() {  synchronized(this) {    int temp = i;    i = temp + 5;  }}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/404788.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号