【问题标题】:Using boolean to synchronize使用布尔值进行同步
【发布时间】:2017-06-03 06:36:29
【问题描述】:
以下代码在并发访问 List 时是线程安全的吗?
volatile 限定符是否在这里增加了任何价值?
class concurrentList{
private AtomicBoolean locked = new AtomicBoolean(true);
volatile List<Integer> list=new LinkedList<Integer>();
long start = System.currentTimeMillis();
long end = start + 60*100;
public void push(int e){
while(!locked.get());
list.add(e);
while(!locked.compareAndSet(true,false));
}
public int pop(){
int elem;
while(locked.get());
elem=(Integer)list.remove(0);
while(!locked.compareAndSet(false,true));
return elem;
}
....
}
【问题讨论】:
标签:
java
concurrency
java.util.concurrent
【解决方案1】:
不,它不是线程安全的。两个调用push() 的线程可以完美地将locked 读为true,然后并发添加到链表中。由于 LinkedList 不是线程安全的,因此您的代码也不是线程安全的。
要锁定,请使用锁定,而不是 AtomicBoolean。
【解决方案2】:
在这种情况下,我建议使用ReadWriteLock。这把锁有两个用途。当 readLock 开启时,不允许读,直到写锁被释放。读锁是非阻塞的:
class concurrentList{
ReadWriteLock lock =new ReentrantReadWriteLock();
private AtomicBoolean locked = new AtomicBoolean(true);
volatile List<Integer> list=new LinkedList<Integer>();
long start = System.currentTimeMillis();
long end = start + 60*100;
public void push(int e){
lock.writeLock().lock();
try{
list.add(e);
} finally {
lock.writeLock().unlock();
}
}
public int pop(){
lock.readLock().lock();
try {
int elem;
elem=(Integer)list.remove(0);
} finally {
lock.readLock().unlock();
}
return elem;
}
....
}
【解决方案3】:
在这种特殊情况下,我将根据[this question][1] 对方法使用同步,而不是对变量使用易失性
类并发列表{
private AtomicBoolean locked = new AtomicBoolean(true);
List<Integer> list=new LinkedList<Integer>();
long start = System.currentTimeMillis();
long end = start + 60*100;
public synchronized void push(int e){
while(someLock.notCondition()); //only an example
list.add(e);
someLock.notify();
}
public synchronized int pop(){
int elem;
while(someLock.notCondition());
elem=(Integer)list.remove(0);
someLock.notify()
return elem;
}
....
}
【解决方案4】:
在已经添加的答案中添加更多内容,即对于任何并发编程三个概念,您在编写线程安全编程时需要考虑。当未正确编写并发程序时,错误往往属于以下三类之一: Aomicity、Visibility 或 Ordering。
原子性:处理哪些动作和动作集具有不可分割的效果。通常从互斥的角度来考虑。
可见性:确定一个线程的效果何时可以被另一个线程看到。
排序:确定何时可以看到一个线程中的操作相对于另一个线程发生无序
在您的代码第一个问题中,上述所有概念都失败了。您没有使用锁定,因此无法确保可见性和顺序。
为了线程安全,您可以在并发 API 中使用ReadWriteLock。或者有可用的非阻塞链表将使用 compareAndset。