首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >这个双重检查的锁是不是没有被破坏?

这个双重检查的锁是不是没有被破坏?
EN

Stack Overflow用户
提问于 2014-11-19 06:37:18
回答 1查看 82关注 0票数 0

这个article解释了“双重检查锁定”,其思想是减少锁争用。正如这篇文章所解释的那样,它不起作用。参见表中的代码示例“(仍然)损坏的多线程版本”双重检查锁定“惯用法”。

现在我想我找到了一个可以工作的变体。问题是这是否正确。假设我们有一个消费者和一个生产者,它们通过共享队列交换数据:

代码语言:javascript
复制
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发生变化时,只进入消费者中的同步块。

EN

Stack Overflow用户

发布于 2014-11-19 23:35:25

我怀疑你更多的是在找一个Code Review

您应该考虑以下几点:

  • 这不是双重检查锁定。
  • 你的消费者将什么都不旋转,在没有数据到达的时候吃掉cpu。

  • ,你使用AtomicInteger作为信号量。
  • BlockingQueue将为您完成所有这些操作。
  • 您尚未正确确保共享updateCount
  • 您不必在原子上进行同步。

这里有一个简单的生产者/消费者对用于演示。

代码语言:javascript
复制
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();
    }

}
票数 3
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27005481

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档