Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/384.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Object.wait何时被调用_Java_Multithreading - Fatal编程技术网

Java Object.wait何时被调用

Java Object.wait何时被调用,java,multithreading,Java,Multithreading,当我们有一个线程正在执行一个同步块,而另一个线程试图访问该同步块时 是否会在被阻止的线程上自动调用Object.wait 另外,我看到在对象类中,等待的定义是: public final native void wait(长超时)抛出InterruptedException 这是否意味着我们必须在类中手动编写下面的函数。我见过很多例子: public void doWait(){ synchronized(obj){ while(!wasSignalled){

当我们有一个线程正在执行一个同步块,而另一个线程试图访问该同步块时

  • 是否会在被阻止的线程上自动调用Object.wait
  • 另外,我看到在对象类中,等待的定义是:

    public final native void wait(长超时)抛出InterruptedException

  • 这是否意味着我们必须在类中手动编写下面的函数。我见过很多例子:

    public void doWait(){
        synchronized(obj){
          while(!wasSignalled){
            try{
              obj.wait();
             } catch(InterruptedException e){...}
          }
          //clear signal and continue running.
          wasSignalled = false;
        }
      }
    
    public void doNotify(){
        synchronized(obj){
          wasSignalled = true;
          obj.notify();
        }
      }
    
    是否会在被阻止的线程上自动调用Object.wait

    不太可能,它会阻塞监视器锁。您可以参考文档。无论如何,有关如何在内部执行此操作的详细信息与使用
    synchronized
    并不相关,您可以使用它,因为您知道在任何给定时间只允许一个线程执行synchtonized块

    这是否意味着我们必须手动编写一个函数,如 在我们班下面


    不,这是为你做的。同步块一次只能由一个线程访问,因此第二个线程将阻塞,直到第一个线程退出同步块。

    否,
    Object::wait
    等待
    /
    通知
    机制是由
    同步
    提供的基本锁定之上的附加层;可以使用
    synchronized
    ,而无需使用
    wait
    notify

    基本的
    synchronized
    机制基于锁定和解锁连接到特定对象的锁(锁有时称为监视器)的思想。如果一个线程锁定了锁,那么另一个试图锁定它的线程将阻塞。当第一个线程解锁锁时,第二个线程解锁,并继续锁定锁

    wait
    /
    notify
    机制为线程提供了一种临时放弃其持有的锁的方法,同时该锁的重新获取由另一个同时持有该锁的线程控制。考虑这个代码:

    public synchronized void first() {
        System.out.println("first before");
        wait();
        System.out.println("first after");
    }
    
    public synchronized void second() {
        System.out.println("second before");
        notify();
        System.out.println("second after");
    }
    
    假设一个线程,线程A,首先调用
    ,然后另一个线程B,调用
    第二个
    。事件的顺序是:

  • A试图获得锁
  • A成功获取锁
  • A在System.out中写入“前一个”
  • B试图获得锁
  • B无法获取锁,因为A拥有它,所以它会阻塞
  • A完成写入,并调用
    等待
    ——此时A释放锁并开始等待
  • B现在成功获取锁,并解除阻塞
  • B向System.out写入“第二个之前”
  • B完成写入,并调用
    notify
    -这对B没有影响,但这意味着A停止等待并尝试重新获取锁
  • A无法获取锁,因为B拥有它,所以它会阻塞
  • B向System.out写入“第二个之后”
  • B完成该方法,并释放锁
  • A现在成功获取锁,并解除阻止
  • A继续并向System.out写入“先到后”
  • A完成该方法,并释放锁
  • 这是一个冗长的描述,但实际上是一个相当简单的过程,
    wait
    /
    notify
    调用让第一个线程将锁借给另一个线程使用

    重要的是要意识到有两种不同类型的阻塞正在发生。首先,线程在进入
    synchronized
    块(或从
    wait
    调用返回时重新输入一个)时阻塞等待获取锁的方式。其次,线程在调用
    wait
    后阻塞,然后被相应的
    notify
    解除阻塞

    我将
    等待
    /
    通知
    描述为一个线程将锁借给另一个线程。这就是我的想法,我认为这是一个富有成效的比喻。用一个局部恐怖的比喻,也许这就像一个吸血鬼搬进城堡,然后睡在棺材里。一旦他睡着了,一些无辜的游客进来把城堡出租作为度假之家。在某个时刻,游客们探索地下室,扰乱了棺材,这时吸血鬼醒来,想要回他的城堡。一旦游客们在恐惧中逃离,他就可以搬回房子里

    之所以
    wait
    notify
    具有它们的名称,而不是像
    lend
    return
    这样的名称,是因为它们通常用于构建线程间通信机制,其中重点不是第一个线程最初借出锁,但当侍者被第二根线唤醒时

    现在,最后谈谈你的第二个问题,有两件事需要考虑

    第一个是“虚假唤醒”的可能性——请参阅Java语言规范第节中嵌套的项目符号列表中的小注释:

    由于[…]实现的内部操作,可能会从等待集中删除线程。允许实现(尽管不鼓励)执行“伪唤醒”,即从等待集中删除线程,从而在没有明确指令的情况下实现恢复

    也就是说,线程通常只在收到通知时才会唤醒,但也有可能在未收到通知时随机唤醒。因此,您确实需要使用一个循环来保护
    wait
    ,该循环涉及对条件变量的检查,就像您的示例中一样。如说明书所述:

    注意,这一规定要求Java编码实践只在循环中使用wait,循环只有在线程等待等待等待的逻辑条件下才会终止

    第二个是中断。中断不是随机的;inte