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

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地址

原文地址:https://www.cnblogs.com/falco/p/9382715.html