简体   繁体   English

这是不间断的双重检查锁定吗?

[英]Is this Double-Checked Locking that is not Broken?

This article explains "Double-Checked Locking" where the idea is to reduce lock contention. 本文介绍了“双重检查锁定”,其思想是减少锁定争用。 As the article explains it does not work. 如文章所述,它不起作用。 See the code sample in the table "(Still) Broken multithreaded version "Double-Checked Locking" idiom". 请参阅表“(仍然)断掉的多线程版本“ Double-Checked Locking”惯用语”中的代码示例。

Now I think I found a variant that should work. 现在,我认为我发现了应该起作用的变体。 Question is whether that is correct. 问题是那是否正确。 Let's say we have a consumer and a producer that exchange data through a shared queue: 假设我们有一个使用者和一个生产者,它们通过一个共享队列交换数据:

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();
                }
            }
        }
    }
}

Question now is whether you think this approach works. 现在的问题是您是否认为此方法有效。 I'm asking to be sure, because tons of things would break if it doesn't ... The idea is to reduce lock contention when only entering a synchronized block in the consumer when the updateCount has changed in the meanwhile. 我要确保,因为如果不这样做,那么很多事情都会中断……这个想法是在updateCount发生变化的同时仅在使用者中输入同步块时减少锁争用。

I suspect you are looking more for a Code Review . 我怀疑您正在寻找更多的《代码审查》

You should consider the following: 您应该考虑以下几点:

  • This is not double-checked locking. 这不是双重检查锁定。
  • Your consumer will spin on nothing and eat cpu while no data is arriving. 您的消费者将无动于衷,在没有数据到达时吃掉CPU。
  • You use an AtomicInteger as a Semaphore. 您将AtomicInteger用作信号量。
  • A BlockingQueue will do all of this for you. 一个BlockingQueue将为您完成所有这些工作。
  • You haven't properly ensured that updateCount is shared. 您尚未正确确保updateCount是共享的。
  • You do not have to synchronize on atomics. 您不必在原子上进行同步。

Here's a simple Producer/Consumer pair for demonstration. 这是一个简单的生产者/消费者对进行演示。

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();
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM