可以等待再次唤醒上下文切换的线程

时间:2014-10-19 13:36:58

标签: java multithreading wait producer-consumer context-switch

我正在努力让我的制作人/消费者工作,我故意不想在这里使用BlockingQueue来理解更精细的细节。我理解当我调用object.wait()时,线程会松开其锁定并进入WAITING状态,直到有人通知(notify / notifyAll),它将其恢复为BLOCKED状态,如果获取锁定,该线程将转到RUNNABLE。

    private class Consumer implements Runnable{
        private final MyQueue<Integer> queue;
        public Consumer(MyQueue<Integer> queue){
            this.queue = queue;
        }
        @Override
        public void run(){
            while(true){
                synchronized (queue) {
                    //Block till new available
                    while(queue.isEmpty()){
                        try {
                            queue.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //Consume
                    queue.dequeue();
                    queue.notifyAll(); //Notify people waiting on queue full condition
                }
            }
        }
    }

我的问题是(就上面的代码而言):

  1. 我的线程正在等待,等待后醒来(有人通知) 我拿到了锁
  2. 我做了一个check queue.isEmpty()并且它不是空的,执行进入下一行
  3. 就在下一行queue.dequeue()执行之前,CPU上下文切换了我的线程。
  4. 接下来当我得到我的cpu切片并锁定时,我运行queue.dequeue()并说队列是空的
  5. 我知道通常的CPU调度程序会为每个线程提供一定的时间来避免上下文切换成本。

1 个答案:

答案 0 :(得分:1)

这种情况不会发生,正是因为对队列的任何修改都是(或者至少应该)从队列上的同步块完成的。因此,没有其他线程可以在while循环结束和dequeue()调用之间修改队列,因为你的线程是持有锁的线程。

当然,如果某个其他使用者也在队列中删除元素而没有在队列上同步,那么您将遇到此问题。但那只是你代码中的错误。使用封装是避免这些类型的错误的最佳方法。如果您使用了BlockingQueue,则BlockingQueue类将封装对共享状态的独占访问,并且您不必确保对队列的每次访问都已正确同步,因为BlockingQueue会为您执行此操作。