两种同步方式的区别

Difference between two synchronization methods

我怀疑 java 线程同步让我有些困惑,如果我有一个共享内存区,在同步方法中使用 wait/notify/notifyAll 和声明一个对象有什么区别(Object myObj) 并使用 myObj.wait,据我所知两者都达到了相同的效果。

换句话说: 这个

public class ThreadSignal{
    protected boolean isDataAvailable = false;
    public void synchronized waitUntilComplete(){
       if(isDataAvailable == false){
           wait();
       }
    }
    public void synchronized complete(){
       isDataAvailable = true;
       notify();
    }
}

对比这个

private Object notEmpty = new Object();
private Object notFull = new Object();
public synchronized E take() {
        //some code
            notEmpty.wait()
        //some code
        notFull.notifyAll();
}

区别在于第一个锁定整个对象,因此没有其他线程可以访问该共享区域,而在第二个中,我们在想要锁定的内容上有更大的灵活性?

第二个问题,因为很难将其放入评论中(为此编辑主要 post):

我有一个问题,我正在尝试解决并找出构建 class 的最佳方法,问题如下有一个机场有一个队列(共享区域)和三个线程(飞行员、女主人和passenger),女主人基本就是机场check in了

乘客先入队,等待女主人的checkDocuments操作(所以进入blocking/waiting状态),然后出示机票,等待女主人的waitForNextPassenger操作进入队列飞机。女主人则被乘客的waitInQueue操作唤醒(刚入队时),检查乘客,然后进入另一个等待状态,等待乘客文件,然后检查乘客。

鉴于此,我定义了这些阻塞变量: 排队等候 检查文件 展示文件 waitForNextPassenger

鉴于您在评论中所说的内容,我想一个好的方法是使每个对象成为一个对象,例如在线程乘客生命周期中,它将调用方法 WaitInQueue 等待对象 checkDocuments (checkDocuments.wait) 女主人会 checkDocuments.notify

这是正确的方法吗?

同步方法:

public void synchronized f() {...}

等同于:

public void f() {
  synchronized(this) {
  ...
  }
}

不同于:

private Object obj=new Object()

public void f() {
  synchronized(obj) {
    ...
   }
}

同步方法使用this,这意味着在同一对象上工作的任何其他同步方法将等待当前同步方法returns。当你使用带有同步块的单独对象时,同步块将等待直到使用相同对象的当前同步块退出。所以用第二种方法,你可以这样做:

public void f() {
   synchronized(obj) {
     ...
   }
   // Do stuff
   synchronized(obj) {
    ...
   }
}

也就是可以更细粒度的控制互斥

第二种方法也允许您锁定多个对象。

当你使用第二种方法时,你必须小心wait/notify。如果您持有 obj 的锁,则可以调用 obj.wait(),这意味着您处于同步块 synchronized(obj) 中。当调用 wait 时,同步块将放弃对该对象的锁定。然后,另一个线程可以使用 obj.notify() 向等待线程发送通知。