java - 这是没有被破坏的双重检查锁定吗?

标签 java multithreading concurrency synchronized

这个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/

相关文章:

java - 属性文件中的屏蔽

java - 对 Java protocol buffers 对象做一些小改动

Java、多线程和 Raspberry Pi

multithreading - 为什么我的程序用一个核心而不是两个核心更快?

javascript - 告诉javascript停止执行代码并在函数中间做后台工作

Java 并发 : How can I tell which Future belongs to which Callable during processing?

java - 将大数据流式传输到 Apache Nifi 中的流文件,无需 OOM

c# - Windows窗体中的线程

c# - Windows 服务不执行代码

java - 为了获得最大性能,线程池的大小应该是多少?