\本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法。java
①wait() 与 notify/notifyAll 方法必须在同步代码块中使用编程
②wait() 与 notify/notifyAll() 的执行过程api
③中断 调用wait()方法进入等待队列的 线程多线程
④notify 通知的顺序不能错ide
⑤多线程中测试某个条件的变化用 if 仍是用 while?学习
wait() 与 notify/notifyAll() 是Object类的方法,在执行两个方法时,要先得到锁。测试
咱们常常使用synchronized关键字得到锁。所以,wait()与notify/notifyAll()常常与synchronized搭配使用,即在synchronized修饰的同步代码块或方法里面调用wait() 与 notify/notifyAll()方法。this
不在synchronized关键字中使用,会抛出异常。spa
因为 wait() 与 notify/notifyAll() 是放在同步代码块中的,所以线程在执行它们时,确定是进入了临界区中的,即该线程确定是得到了锁的。线程
当线程执行wait()时,会把当前的锁释放,而后让出CPU,进入等待状态。
当执行notify/notifyAll方法时,会唤醒一个处于等待该 对象锁 的线程,而后继续往下执行,直到执行完退出对象锁锁住的区域(synchronized修饰的代码块)后再释放锁。
从这里能够看出,notify/notifyAll()执行后,并不当即释放锁,而是要等到执行完临界区中代码后,再释放。故,在实际编程中,咱们应该尽可能在线程调用notify/notifyAll()后,当即退出临界区。即不要在notify/notifyAll()后面再写一些耗时的代码。
示例以下:
1 public class Service { 2 3 public void testMethod(Object lock) { 4 try { 5 synchronized (lock) { 6 System.out.println("begin wait() ThreadName=" 7 + Thread.currentThread().getName()); 8 lock.wait(); 9 System.out.println(" end wait() ThreadName=" 10 + Thread.currentThread().getName()); 11 } 12 } catch (InterruptedException e) { 13 e.printStackTrace(); 14 } 15 } 16 17 public void synNotifyMethod(Object lock) { 18 try { 19 synchronized (lock) { 20 System.out.println("begin notify() ThreadName=" 21 + Thread.currentThread().getName() + " time=" 22 + System.currentTimeMillis()); 23 lock.notify(); 24 Thread.sleep(5000); 25 System.out.println(" end notify() ThreadName=" 26 + Thread.currentThread().getName() + " time=" 27 + System.currentTimeMillis()); 28 } 29 } catch (InterruptedException e) { 30 e.printStackTrace(); 31 } 32 } 33 }
在第3行的testMethod()中调用 wait(),在第17行的synNotifyMethod()中调用notify()
从上面的代码能够看出,wait() 与 notify/notifyAll()都是放在同步代码块中才可以执行的。若是在执行wait() 与 notify/notifyAll() 以前没有得到相应的对象锁,就会抛出:java.lang.IllegalMonitorStateException异常。
在第8行,当ThreadA线程执行lock.wait();这条语句时,释放得到的对象锁lock,并放弃CPU,进入等待队列。
当另外一个线程执行第23行lock.notify();,会唤醒ThreadA,可是此时它并不当即释放锁,接下来它睡眠了5秒钟(sleep()是不释放锁的,事实上sleep()也能够不在同步代码块中调用),直到第28行,退出synchronized修饰的临界区时,才会把锁释放。这时,ThreadA就有机会得到另外一个线程释放的锁,并从等待的地方起(第9行)起开始执行。
接下来是两个线程类,线程类ThreadA调用testMethod()方法执行lock.wait();时被挂起,另外一个线程类ThreadB调用synNotifyMethod()负责唤醒挂起的线程。代码以下:
public class ThreadA extends Thread { private Object lock; public ThreadA(Object lock) { super(); this.lock = lock; } @Override public void run() { Service service = new Service(); service.testMethod(lock); } } public class ThreadB extends Thread { private Object lock; public ThreadB(Object lock) { super(); this.lock = lock; } @Override public void run() { Service service = new Service(); service.synNotifyMethod(lock); } } public class Test { public static void main(String[] args) { Object lock = new Object(); ThreadA a = new ThreadA(lock); ThreadB b = new ThreadB(lock); a.start(); b.start(); } } 输出结果: begin wait() ThreadName=Thread-0 begin notify() ThreadName=Thread-1 time=1554183779889 end notify() ThreadName=Thread-1 time=1554183784889 end wait() ThreadName=Thread-0
Object类中与线程有关的方法:
1)notify/notifyAll
2)wait()/wait(long)
java.lang.Thread中与之相关的方法:
1)interrupt()
2)sleep()/sleep(long)
3)join()/suspend()/resume()....
使用线程的interrupt()方法,能够终止处于阻塞状态中的线程。api介绍以下:
调用线程的wait(), wait(long)或wait(long, int)会让它进入等待(阻塞)状态,或者调用线程的join(), join(long), join(long, int), sleep(long), sleep(long, int)也会让它进入阻塞状态。若线程在阻塞状态时,调用了它的interrupt()方法,那么它的“阻塞状态”会被清除而且会收到一个InterruptedException异常。例如,线程经过wait()进入阻塞状态,此时经过interrupt()中断该线程;调用interrupt()会当即将线程的中断标记设为“true”,可是因为线程处于阻塞状态,因此该“中断标记”会当即被清除为“false”,同时,会产生一个InterruptedException的异常。
实例以下:
1 public class Test { 2 3 public static void main(String[] args) { 4 5 try { 6 Object lock = new Object(); 7 8 ThreadA a = new ThreadA(lock); 9 a.start(); 10 11 Thread.sleep(5000); 12 13 a.interrupt(); 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 } 18 } 输出结果: java.lang.InterruptedException: wait interrupted at java.lang.Thread.sleep(Native Method) at Thread3.run(Thread3.java:13)
假设在线程A中执行wait(),在线程B中执行notify()。但若是线程B先执行了notify()而后结束了,线程A才去执行wait(),那此时,线程A将没法被正常唤醒了(还能够经过③中提到的interrupt()方法以抛出异常的方式唤醒)。
之前一直不明白 当在线程的run()方法中须要测试某个条件时,为何用while,而不用if?
有两个线程从List中删除数据,而只有一个线程向List中添加数据。初始时,List为空,只有往List中添加了数据以后,才能删除List中的数据。添加数据的线程向List添加完数据后,调用notifyAll(),唤醒了两个删除线程,可是它只添加了一个数据,而如今有两个唤醒的删除线程,这时怎么办??
若是用 if 测试List中的数据的个数,则会出现IndexOutofBoundException,越界异常。缘由是,List中只有一个数据,第一个删除线程把数据删除后,第二个线程再去执行删除操做时,删除失败,从而抛出 IndexOutofBoundException。
可是若是用while 测试List中数据的个数,则不会出现越界异常.