我正在努力让我的制作人/消费者工作,我故意不想在这里使用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
}
}
}
}
我的问题是(就上面的代码而言):
我知道通常的CPU调度程序会为每个线程提供一定的时间来避免上下文切换成本。
答案 0 :(得分:1)
这种情况不会发生,正是因为对队列的任何修改都是(或者至少应该)从队列上的同步块完成的。因此,没有其他线程可以在while循环结束和dequeue()
调用之间修改队列,因为你的线程是持有锁的线程。
当然,如果某个其他使用者也在队列中删除元素而没有在队列上同步,那么您将遇到此问题。但那只是你代码中的错误。使用封装是避免这些类型的错误的最佳方法。如果您使用了BlockingQueue,则BlockingQueue类将封装对共享状态的独占访问,并且您不必确保对队列的每次访问都已正确同步,因为BlockingQueue会为您执行此操作。