Object中线程阻塞及唤醒方法的使用

隐身守侯 提交于 2020-02-23 11:59:50

Object中线程阻塞及唤醒方法使用

相关方法

挂起: wait()/wait(long timeout)/wait(long timeout, int nanos)

唤醒: notify()/notifyAll()

使用说明

  • 调用对象的这些方法(wait/notify),必须先持有对象的监视器(monitor);否则会抛出IllegalMonitorStateException异常

    例1:

    public static void main(String[] args) {
      Thread th1 = new Thread(){
          @Override
          public void run() {
              try {
                  this.wait();
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      };
    
      th1.start();
    }

    运行结果:

    Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
    
      at java.lang.Object.wait(Native Method)
    
      at java.lang.Object.wait(Object.java:503)
    
      at com.falco.src.verify.ObjectVerification$1.run(ObjectVerification.java:11)
  • 当调用对象的wait方法后,线程处于阻塞状态,对应的监视器(monitor)也被释放,其他线程可以获得此监视器来唤醒该线程。当线程重新被唤醒时,它会再次获取该监视器(monitor),然后被唤醒

唤醒方式

调用wait方法后,线程处于阻塞状态。可以通过以下四种唤醒方式:

  1. 调用notify/notifyAll方法唤醒

    例二:

    public static void main(String[] args) {
         final Object bt = new Object();
         Thread th1 = new Thread() {
             @Override
             public void run() {
                 try {
                     synchronized (bt) {
                         bt.wait();
                         System.out.println("the thread has been woke up.");
                     }
                 } catch (InterruptedException e) {
                     System.out.println("the current thread has been interupted.");
                     e.printStackTrace();
                 }
             }
         };
         th1.start();
    
         Thread th2 = new Thread() {
             @Override
             public void run() {
                 synchronized (bt) {
                     bt.notify();
                     System.out.println("finish waking up.");
                 }
             }
         };
         th2.start();
         System.out.println("wait the program exit.");
     }

    结果:

    wait the program exit.
    finish waking up.
    the thread has been woke up.
  2. 超时自动唤醒,即:wait方法指定一个超时时间,达到这个超时时间且没有被唤醒的线程将自动唤醒

    例三:

     public static void main(String[] args) {
         final Object bt = new Object();
         Thread th1 = new Thread() {
             @Override
             public void run() {
                 try {
                     synchronized (bt) {
                         bt.wait(10,1);
                         System.out.println("the thread has been woke up.");
                     }
                 } catch (InterruptedException e) {
                     System.out.println("the current thread has been interupted.");
                     e.printStackTrace();
                 }
             }
         };
         th1.start();
         System.out.println("wait the program exit.");
     }

    运行结果:

    wait the program exit.
    the thread has been woke up.
  3. 中断唤醒,在其他线程中,调用阻塞线程的中断方法,从而唤醒阻塞的线程

    例四:

    public static void main(String[] args) {
         Thread th1 = new Thread() {
             @Override
             public void run() {
                 try {
                     synchronized (this) {
                         this.wait();
                     }
                 } catch (InterruptedException e) {
                     System.out.println("the current thread has been interupted.");
                     e.printStackTrace();
                 }
             }
         };
    
         th1.start();
         System.out.println("before interrupting,the interrupt flag:"+th1.isInterrupted());
         th1.interrupt();
         System.out.println("after interrupting,the interrupt flag:"+th1.isInterrupted());
     }

    运行结果:

    before interrupting,the interrupt flag:false
    after interrupting,the interrupt flag:true
    the current thread has been interupted.
    java.lang.InterruptedException
     at java.lang.Object.wait(Native Method)
     at java.lang.Object.wait(Object.java:503)
     at com.falco.src.verify.ObjectVerification$1.run(ObjectVerification.java:11)
  4. 假醒(spurious wakeup),除了以上三种方式外,处于阻塞中的线程还可能自动被唤醒

    由于假醒的存在,因此需要自行处理假醒的场景,通过下面的形式排出假醒,避免程序出错

    ...
    synchronized (bt) {
        while (condition) {//condition为不满足唤醒条件,即不满足唤醒条件时执行循环
         bt.wait();
        }
    }
    ...

    假醒相关内容就不在这里介绍了,如果有兴趣,请自行研究

    假醒wiki地址

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!