【问题标题】:Difference between two synchronization methods两种同步方式的区别
【发布时间】:2021-03-30 18:46:38
【问题描述】:

我怀疑在 java 线程同步中让我有些困惑,如果我有一个共享内存区域,那么在同步方法中使用 wait/notify/notifyAll 和声明一个 Object (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();
    }
}

vs这个

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

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

第二个问题,因为将其放在评论中很难(为其编辑主要帖子):

我有一个问题我试图解决并找出构建课程的最佳方法,问题如下有一个带有队列(共享区域)和三个线程(飞行员、女主人和乘客)的机场,女主人是基本上是从机场办理登机手续。

乘客首先进入队列等待女主人的操作checkDocuments(因此进入阻塞/等待状态)然后出示机票并等待女主人的操作waitForNextPassenger进入机内。另一方面,女主人被乘客的 waitInQueue 操作唤醒(当它第一次进入队列时),检查乘客,然后进入另一个等待状态,等待乘客文件,然后检查乘客。

鉴于此,我定义了这些阻塞变量: 等待队列 检查文件 展示文件 等待下一个乘客

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

这是一个正确的方法吗?

【问题讨论】:

  • 嗯,它们只是不同而已。一个区别是第一个锁定整个对象,因此锁定是外部的,并且对任何引用该对象的人都是可见的。但锁定策略似乎也不同(两个锁对一个),notify()notifyAll() 做不同的事情。
  • 好吧,我放置的示例不同,但我可以通过技术上执行 Object isDataAvailable; 来完成第一个示例;然后不是等待,而是执行 isDataAvailable.wait,然后执行 isDataAvailable.notify。主要区别是什么

标签: java multithreading synchronization


【解决方案1】:

同步方法:

public void synchronized f() {...}

等同于:

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

不同于:

private Object obj=new Object()

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

同步方法使用this,这意味着在同一对象上工作的任何其他同步方法都将等待当前同步方法返回。当您将单独的对象与同步块一起使用时,同步块将一直等到使用同一对象的当前同步块退出。因此,使用第二种方法,您可以这样做:

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

也就是说,您可以以更精细的方式控制互斥。

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

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

【讨论】:

  • 假设我有一个共享区域将由三个线程共享,并且共享区域有多个线程将使用的“信号”,越细化的方法越好我会假设?
  • 我不明白关于“多信号”的部分。也许您可以更新问题以包含这部分?
  • 编辑了主帖!
  • 您似乎将程序状态与锁混淆了。据我所知,您有一个共享资源,即队列,您需要对其进行同步。旅客到达时需要锁定,然后选择一名旅客进行处理。
  • 啊,看来我确实搞混了,那我怎么能保证一系列事件呢?例如,如果我有 10 名乘客在等待共享区域的锁定,那么女主人会通知他们所有人尝试使用 notifyAll 办理登机手续,其中一人去办理登机手续并等待女主人再次通知他,如果女主人现在再次通知(因此释放共享区域),它不会唤醒其他乘客线程之一并最终出现两个线程签入的情况吗?
猜你喜欢
  • 2019-02-27
  • 1970-01-01
  • 2011-02-25
  • 1970-01-01
  • 1970-01-01
  • 2018-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多