【问题标题】:can waiting thread which woke up context switch again可以等待唤醒上下文的线程再次切换
【发布时间】:2014-10-19 13:36:57
【问题描述】:

我正在尝试让我的生产者/消费者正常工作,但我故意不想在这里使用 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. 我做了一个检查 queue.isEmpty(),它不是空的,执行到下一行
  3. 就在执行下一行 queue.dequeue() 之前,CPU 上下文切换了我的线程。
  4. 接下来,当我获得 CPU 切片并锁定时,我运行 queue.dequeue() 并说队列为空

我知道通常的 CPU 调度程序会为每个线程分配一定的时间,以避免上下文切换成本。

【问题讨论】:

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


    【解决方案1】:

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

    当然,如果其他消费者也从队列中删除了元素而没有在队列上同步,你就会遇到这个问题。但这只是您代码中的一个错误。使用封装是避免此类错误的最佳方法。如果您使用 BlockingQueue,BlockingQueue 类将封装对共享状态的独占访问,您不必确保对队列的每次访问都正确同步,因为 BlockingQueue 会为您完成。

    【讨论】:

    • 上下文切换的线程是否持有锁并退出执行?
    • 线程保持锁直到它离开同步块。线程当前是否正在执行不会改变任何东西。如果调度器决定在while循环之后和dequeue调用之前切换到其他线程,所有其他等待锁的线程将一直被阻塞,直到持有锁的线程被重新调度,并继续执行直到它离开同步块。
    • 谢谢!这很清楚“线程保持锁定直到它离开同步块。线程当前是否正在执行不会改变任何东西”。虽然有趣的是,当操作系统上下文切换时,它可能会减慢等待锁定的线程
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-31
    • 1970-01-01
    • 2015-04-08
    • 2021-08-09
    • 2010-10-29
    • 1970-01-01
    相关资源
    最近更新 更多