在线程安全对象上需要同步是什么

时间:2014-09-27 14:36:41

标签: java multithreading vector thread-safety synchronized

我正在网络搜索生产者消费者问题,我得到了this link。 程序员在这里使用 Vector 作为sharedqueue

我想为什么我需要一个同步块,因为 Vector 已经是线程安全的。它必须自己处理线程。

但是当我试图删除同步块时。它给了我一个IllegalMonitorStateException。以下是生产方法

的代码段
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 个答案:

答案 0 :(得分:2)

如果没有同步,你可以这样做:

Producer Thread              Consumer Thread                  
                             if (sharedQueue.isEmpty) {
sharedQueue.add(i);
sharedQueue.notifyAll();
                                  sharedQueue.wait()
                             }

因此,即使队列中有数据,消费者线程也可能永远等待,因为在测试数据之间添加了东西,并且它开始等待有关添加数据的通知。

当然有一些解决方法,例如wait上的超时,但这些都有轮询开销,轮询间隔导致的延迟,丑陋的代码等等。当你可以使用同步时,没有理由诉诸这些事情。


那么为什么队列类是线程安全的呢?好吧,线程安全类不是魔法!线程安全只是意味着,对该类实例的单个方法调用是线程安全的。因此,例如,如果两个线程同时对同一个实例执行add,则不会损坏任何内容,使用另一个执行操作擦除一个操作,或者类似的任何操作。

但是如果你有多个线程进行多个操作,那么它们可以是交错的,这毕竟是许多线程和先发制人的多任务处理的重点!那么交错操作会发生什么,这取决于操作。例如,许多仅执行add的线程会以某种未指定的顺序添加内容,但这可能没问题。但是当您不希望操作以“随机”顺序发生时,您需要使用同步。

如上例所示,在这种情况下,即使队列中的数据,“随机”顺序也可能导致消费者无限期地等待。事实上,如果你有序列“做修改,通知服务员”,服务员做“看看有没有做的事情,否则等待”,你有同样的问题,并且必须使用修改通知和查等待。


你得到错误,因为Java要求你在通知时拥有锁,因为如上所述,没有锁就没有意义,它总是一个错误,一个错误。这不是特定于Java的,这是这种机制的基础,它们总是需要锁定,在Wikipedia article section阅读更多内容。