JAVA中的Object是所有类的父类,鉴于继承机制,java把所有类都需要的方法放到了Object类中,其中就有线程的通知和等待系列的方法
1、wait()方法
当一个线程调用一个共享变量的wait()方法的时候,该调用线程就会被阻塞挂起,知道发生以下几种情况,该线程才会被重新唤醒
1、其他线程调用了该共享对象的notify()或者notifyAll()方法
例如:
执行结果:
以上的两个线程,线程一调用了共享对象的wait()方法,使线程一进行阻塞挂起,在第二个线程中调用了共享对象的notify()方法,唤醒了当前共享对象调用wait()阻塞挂起的第一个线程,然后第一个线
程继续执行
2、其他线程调用了该线程的interrupt()方法,该线程抛出了InterruptedException异常返回
结果: 线程调用了共享对象的wait()方法阻塞挂起了自己,然后主线程休眠3秒之后中断了thread线程,中断后thread抛出了InterruptedException异常后返回并终止
另外,如果调用wait()方法的线程没有事先获取该对象的监视器锁,则调用wait()方法会抛出IllegalMonitorStateException异常
例如:
执行结果:
线程获取共享变量的监视器锁的方式
1、执行synchronized同步代码块时,使用该共享变量作为参数
synchronized(共享变量){ //不是说使用同步代码块就是获取共享变量的监视器锁,而是在使用同步代码块中将共享变量作为参数才是获取共享变量的监视器锁
}
2、调用该共享变量的方法,并且该方法使用了synchronized修饰
synchronized void add(int a , int b){
}
2、notify()和notifyAll()
1、一个线程调用共享对象的notify()方法后,会唤醒一个在该共享变量上调用wait系列方法后被挂起的线程。一个共享变量上可能有多个线程在等待,具体唤醒哪个等待的线程是随机的。
例如:
public static void main(String[] args) { List queue=new ArrayList(); Thread threadA=new Thread(){ @Override public void run() { synchronized (queue) { System.out.println("线程A运行"); try { System.out.println("线程A挂起"); queue.wait(); System.out.println("线程A结束挂起"); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Thread threadB=new Thread(){ @Override public void run() { synchronized (queue){ System.out.println("线程B运行"); try { System.out.println("线程B挂起"); queue.wait(); System.out.println("线程B结束挂起"); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Thread threadC=new Thread(){ @Override public void run() { synchronized (queue){ System.out.println("线程C唤醒"); queue.notify(); } } }; threadA.start(); threadB.start(); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } threadC.start(); }
执行结果:使用notify() 随机唤醒了线程A 而线程B并没有唤醒
2、一个线程调用共享对象的notify()方法会唤醒该共享对象上的随机的一个被阻塞的线程,而notifyAll()则会唤醒所有在该共享对象上由于调用wait系列方法而被挂起的线程
例如:
public static void main(String[] args) { List queue=new ArrayList(); Thread threadA=new Thread(){ @Override public void run() { synchronized (queue) { System.out.println("线程A运行"); try { System.out.println("线程A挂起"); queue.wait(); System.out.println("线程A结束挂起"); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Thread threadB=new Thread(){ @Override public void run() { synchronized (queue){ System.out.println("线程B运行"); try { System.out.println("线程B挂起"); queue.wait(); System.out.println("线程B结束挂起"); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Thread threadC=new Thread(){ @Override public void run() { synchronized (queue){ System.out.println("线程C唤醒"); queue.notifyAll(); } } }; threadA.start(); threadB.start(); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } threadC.start(); }
结果:使用线程C调用共享对象的notifyAll方法 唤醒了线程A和线程B两个线程;
注意:在共享对象调用notifyAll()的时候,只会唤醒调用这个方法前调用了wait系列函数而被挂起的线程,如果调用了notifyAll()方法之后,一个线程调用了该共享对象的wait()方法而被阻塞挂起,则该线程不会被唤醒。
原文:https://www.cnblogs.com/jisha/p/14635076.html