java在线程安全对象上同步需要什么
我在网上搜索一个生产者消费者问题,我得到了this link。
程序员在这里为sharedqueue
使用了一个向量
我想为什么我需要一个同步块,因为Vector已经是线程安全的了。它必须自己处理线程
但当我试图通过删除同步块来实现时。它给了我一个IllegalMonitorStateException
。下面是product方法的代码片段
private void produce(int i) throws InterruptedException {
//wait if queue is full
while (sharedQueue.size() == SIZE) {
// synchronized (sharedQueue) {
System.out.println("Queue is full " + Thread.currentThread().getName()
+ " is waiting , size: " + sharedQueue.size());
sharedQueue.wait();
// }
}
//producing element and notify consumers
// synchronized (sharedQueue) {
sharedQueue.add(i);
sharedQueue.notifyAll();
// }
}
我的问题是为什么我们需要同步或锁定一个已经线程安全的对象
# 1 楼答案
在不同步的情况下,您可以执行以下操作:
所以,即使队列中有数据,使用者线程也可能永远等待,因为在测试数据和开始等待关于添加数据的通知之间添加了内容
当然也有一些解决办法,比如
wait
上的超时,但这些都有轮询开销、轮询间隔引起的延迟、难看的代码等等。当您可以使用同步时,没有理由求助于这些东西那么,为什么队列类是线程安全的还不够呢?好吧,线程安全类不是魔法!线程安全仅仅意味着,对该类实例的单个方法调用是线程安全的。因此,例如,如果两个线程同时对同一个实例执行
add
,则不会损坏任何内容、用另一个操作擦除一个操作或类似操作但是如果有多个线程执行多个操作,那么它们可以交错,这就是多线程和先发制人多任务的全部意义所在!那么交错操作会发生什么,这取决于操作。例如,许多只执行
add
的线程会以某种未指定的顺序添加内容,但这可能没问题。但当您不希望操作以“随机”顺序发生时,您需要使用同步如上面的示例所示,在这种情况下,“随机”顺序可能导致消费者无限期地等待,即使队列中有数据。事实上,如果您曾经有序列“进行修改,通知侍者”,侍者执行“查看是否有事情要做,否则等待”,那么您也会遇到同样的问题,并且必须在修改通知和检查等待之间使用同步
您会得到错误,因为Java要求您在通知时拥有锁,因为如上所述,没有锁是没有意义的,它总是一个错误,一个bug。这不是Java特有的,这是这类机制的基础,它们总是需要锁,在这个Wikipedia article section阅读更多