有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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) 个答案

  1. # 1 楼答案

    在不同步的情况下,您可以执行以下操作:

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

    所以,即使队列中有数据,使用者线程也可能永远等待,因为在测试数据和开始等待关于添加数据的通知之间添加了内容

    当然也有一些解决办法,比如wait上的超时,但这些都有轮询开销、轮询间隔引起的延迟、难看的代码等等。当您可以使用同步时,没有理由求助于这些东西


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

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

    如上面的示例所示,在这种情况下,“随机”顺序可能导致消费者无限期地等待,即使队列中有数据。事实上,如果您曾经有序列“进行修改,通知侍者”,侍者执行“查看是否有事情要做,否则等待”,那么您也会遇到同样的问题,并且必须在修改通知和检查等待之间使用同步


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