这个article解释了“双重检查锁定”,其中的想法是减少锁争用。正如文章所解释的那样,它不起作用。请参阅表“(仍然)损坏的多线程版本“双重检查锁定”习惯用法”中的代码示例。
现在我想我找到了一个应该可行的变体。问题是这是否正确。假设我们有一个消费者和一个生产者通过共享队列交换数据:
class Producer {
private Queue queue = ...;
private AtomicInteger updateCount;
public void add(Data data) {
synchronized(updateCount) {
queue.add(task);
updateCount.incrementAndGet();
}
}
}
class Consumer {
private AtomicInteger updateCount = new AtomicInteger(0);
private int updateCountSnapshot = updateCount.get();
public void run() {
while(true) {
// do something
if(updateCountSnapshot != updateCount.get()) {
// synchronizing on the same updateCount
// instance the Producer has
synchronized(updateCount) {
Data data = queue.poll()
// mess with data
updateCountSnapshot = updateCount.get();
}
}
}
}
}
现在的问题是您认为这种方法是否有效。我要求确定,因为如果不这样做,很多事情都会中断......这个想法是在 updateCount 同时发生变化时仅在消费者中输入同步块(synchronized block)时减少锁争用。
最佳答案
我怀疑您正在寻找更多Code Review 。
您应该考虑以下事项:
- 这不是双重检查锁定。
- 当没有数据到达时,你的消费者将不运行任何东西并消耗CPU。
- 您使用 AtomicInteger 作为信号量。
- BlockingQueue 将为您完成所有这些工作。
- 您尚未正确确保
updateCount
已共享。 - 您不必在原子上进行同步。
这是一个简单的生产者/消费者对进行演示。
public class TwoThreads {
public static void main(String args[]) throws InterruptedException {
System.out.println("TwoThreads:Test");
new TwoThreads().test();
}
// The end of the list.
private static final Integer End = -1;
static class Producer implements Runnable {
final Queue<Integer> queue;
public Producer(Queue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
for (int i = 0; i < 1000; i++) {
queue.add(i);
Thread.sleep(1);
}
// Finish the queue.
queue.add(End);
} catch (InterruptedException ex) {
// Just exit.
}
}
}
static class Consumer implements Runnable {
final Queue<Integer> queue;
public Consumer(Queue<Integer> queue) {
this.queue = queue;
}
@Override
public void run() {
boolean ended = false;
while (!ended) {
Integer i = queue.poll();
if (i != null) {
ended = i == End;
System.out.println(i);
}
}
}
}
public void test() throws InterruptedException {
Queue<Integer> queue = new LinkedBlockingQueue<>();
Thread pt = new Thread(new Producer(queue));
Thread ct = new Thread(new Consumer(queue));
// Start it all going.
pt.start();
ct.start();
// Wait for it to finish.
pt.join();
ct.join();
}
}
关于java - 这是没有被破坏的双重检查锁定吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27005481/