Java:同步另一个同步对象内的对象

时间:2015-02-27 14:51:35

标签: java multithreading wait synchronized notify

我正在尝试熟悉wait()和notify()方法,并且我已经编写了一个简单的类,就像一个简单的生产者 - 消费者运动的监视器,其中有N个生产者和N个消费者。无论如何,根据练习中的要求,监视器只能存储3个项目。所以生产者必须等待;相反,如果显示器中有0个项目,消费者必须等待。

public class Monitor {

  private List<Integer> items;
  private int capacity;
  private Object waitProducer;
  private Object waitConsumer;
  private int counter;

  public Monitor() {
      this.items = new ArrayList<Integer>();
      this.capacity = 3;
      this.waitProducer = new Object();
      this.waitConsumer = new Object();
      this.counter = 0;
  }

  public void produce() throws InterruptedException {
      synchronized (this) {

          if (this.items.size() == this.capacity) {
              synchronized (this.waitProducer) {
                  System.out.println("Producer " +   Thread.currentThread().getId() + " aspetta");
                  this.waitProducer.wait(); /***/
              }
          }

          counter++;

          System.out.println("Thread " + Thread.currentThread().getId()
                + " produces object " + counter);           

          this.items.add(counter);
          synchronized (this.waitConsumer) {
            this.waitConsumer.notify();
          }

      }
  }

  public void consume() throws InterruptedException {
      synchronized (this) {
          if (this.items.size() == 0) {

              synchronized (this.waitConsumer) {
                  this.waitConsumer.wait(); /***/

              }
          }         

          System.out.println("Thread " + Thread.currentThread().getId()
                + " consume object " + this.items.get(0));

          this.items.remove(0);
          synchronized (this.waitProducer) {
              this.waitProducer.notify();
          }
      }
   }
}

我认为在调用wait()方法时,使用/ *** /:infact存在问题,然后线程会在waitProducer(或waitConsumer)上释放锁,但它不在Monitor对象上。这就是为什么当第一个产生(第一个消费者)时调用wait()然后Monitor对象不再可获得。显然,对Monitor对象的访问必须互斥,以便正确更新列表和计数器。那么,正确的方法是什么?谢谢

2 个答案:

答案 0 :(得分:3)

一次只有一个线程可以在synchronized块内执行代码。

此外,当在该对象上调用synchronized(object)时,必须获得对象的独占锁定(通过wait())。

这意味着,解锁/解除阻塞/通知代码必须可以被称为wait()的原始块之外的其他线程访问。否则,执行将永远等待。

在一个线程等待this.waitConsumer.notify();时,代码中没有其他线程可以到达this.waitProducer.wait();。因为所有这些都包含在synchronized(this)块中,所以其他线程将继续争夺锁定this

答案 1 :(得分:1)

  

@james large如果两个线程在不同的对象上同步,那么这两个线程可以同步在同一个块中是什么意思?

假设您有一个synchronized块,如下所示:

synchronized(obj) {
    ...body of synchronized block...
}
...whatever happens next...

当Java线程T执行该语句时,它首先通过计算表达式obj来开始。该表达式必须返回null,否则必须返回对象的引用。如果它是null,那么将抛出NullPointerException。否则,线程T将尝试锁定对象。

没有两个线程可以同时锁定同一个对象。如果对象已被某个其他线程锁定,则在对象解锁之前,线程T将无法继续。

当线程T最终能够锁定对象时,它将执行同步块的主体,然后它将解锁对象并继续进行接下来发生的任何事情。

这里的重要概念是表达式obj。假设线程T计算obj,获取对象O的引用,锁定它,并进入synchronized块。然后线程U出现,评估obj,得到不同的对象,P。线程U将锁定对象P,并且能够进入同步块,而线程T仍在那里在同一时间。

那怎么会发生呢?

如果有意,可能会是这样的:

class MyClass {
    private final Object lock = new Object();

    void foobar() {
        synchronized(lock) { ... }
    }
}

如果线程T和线程U在MyClass的不同实例上运行,则每个实例都有自己的lock对象。通常,在这种情况下,同步块的主体仅对MyClass的其他实例变量进行操作。由于两个线程在不同的数据上运行,因此它们同时在同一个同步块中没有任何害处。

同步的目的不是为了同时保持两个线程不在同一个方法中:目的是让两个线程不对相同的数据进行操作< / em>同时。


新手程序员有时写这个:

static Integer count = new Integer(0);

...
synchronized(count) {
    count += 1;
    ...operate on static data...
}

这几乎总是一个错误。当线程T进入块时,它将在静态变量count引用的Integer对象上同步。但接下来的事情是更新count以引用不同的整数对象。然后是线程U.U在 new count上同步,并且两个线程都在同一个块中,当它们不应该在相同的静态数据上运行时