请举这个非常简单的例子:
volatile int globalVar = 1;
我的线程:
if (globalVar > 0) {
globalVar--;
}
现在,我必须决定使变量 volatile 是否足以防止竞争条件并使该线程安全。
我知道递增和递减不是,但由于前面的条件,我不确定它是否不同。
我认为它仍然不安全,因为它可以按以下顺序执行:
线程 A 检查条件。线程 B 检查条件。线程 A 递增。线程 B 递增。
我对吗?
请举这个非常简单的例子:
volatile int globalVar = 1;
我的线程:
if (globalVar > 0) {
globalVar--;
}
现在,我必须决定使变量 volatile 是否足以防止竞争条件并使该线程安全。
我知道递增和递减不是,但由于前面的条件,我不确定它是否不同。
我认为它仍然不安全,因为它可以按以下顺序执行:
线程 A 检查条件。线程 B 检查条件。线程 A 递增。线程 B 递增。
我对吗?
你是对的。由于您声明的原因,它不是线程安全的。volatile
确保两个线程都将看到变量的更新值,但不保护多行代码。
不,它不是线程安全的。Volatile 不保证原子性。像 i-- 这样的操作不是原子的,所以将 i 声明为 volatile 没有帮助。
int globalVar = 1;
lock.lock()
try{
if(globalVar > 0)
globalVar--;
}finally {
lock.unlock();
}
上面的代码可以工作,你不需要在这里将 gobalVar 声明为 volatile,因为
Volatile 提供了两个保证:1. 可见性 2. 重新排序
然而
同步/锁定/解锁三保证 1.原子性 2.可见性 3.重排序
还要记住,只要在多个线程之间共享一个对象,总是在任何同步操作同步/易失性读/写下访问该对象。
在这里阅读 JLS 的作者第 17 章的一篇优秀文章。它必须阅读 http://jeremymanson.blogspot.in/2008/11/what-volatile-means-in-java.html http://docs.oracle.com/javase/specs/jls/se7/html/jls -17.html
volatile 不保证原子性。您可以简单地添加一个同步块。
synchronized(this)
{
if (globalVar > 0) {
globalVar--;
}
}
为了使您的代码线程安全,您需要synchronized
在检查和修改周围添加一个块。
可以做的一个例子:
volatile Integer globalVar = 1;
然后在完成工作的方法中,您可以:
synchronized public void decrement(){
if(globalVar > 0)
globalVar--;
}
}