线程间的通信
等待/通知机制
什么是等待通知机制
在单线程中,要执行的操作需要满足一定的条件才能执行,可以把这个操作放在if语句块中。
在多线程中,可能A线程的条件没有满足只是暂时的,稍后可能B线程会更新使得A线程的条件得到满足。所以可以将A线程暂停,直到它的条件得到满足后再将A线程唤醒。伪代码如下:
atomics{ //原子操作 while(条件不成立){ 等待 } 条件满足后,继续执行操作。 }
等待/通知机制的实现
Object类中的wait()方法可以使执行当前代码的线程等待,暂停执行,直到接到通知或被中断为止。
注意:
1.wait()方法只能在同步代码块中由锁对象调用。
2.调用wait()方法,当前线程会释放锁。
伪代码如下:
//在调用wait()方法之前必须获得对象锁
synchronized(锁对象){ while(条件不满足){ 锁对象.wait(); //通过锁对象调用wait()方法暂停线程,会释放锁对象。 } //条件满足,线程向下执行。 }
Object类中的notify()可以唤醒线程,该方法也必须在同步代码块中由锁对象调用。没有使用锁对象调用会抛出illegalMonitorStateExepition异常。如果有多个等待线程,notify()只能唤醒其中的一个。在同步代码块中调用notily()方法后,并不会立即释放锁对象,需要等当前同步代码块执行完后才会释放锁对象,一般将notify()方法放在同步代码块的最后。伪代码如下:
synchronized(锁对象){ //修改保护条件代码 锁对象.notify(); //唤醒其他线程; }
测试代码:
static String lock="lock"; public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new Runnable() { @Override public void run() { synchronized (lock){ System.out.println("线程1开始等待"+" "+System.currentTimeMillis()); try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程1已经唤醒"+" "+System.currentTimeMillis()); } } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { synchronized (lock){ System.out.println("线程2开始唤醒"+" "+System.currentTimeMillis()); lock.notify(); System.out.println("线程2结束唤醒"+" "+System.currentTimeMillis()); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }); t1.start(); Thread.sleep(1000); t2.start(); }
interrupt()方***中断线程的wait()等待
当线程处于wait()等待状态时,调用线程对象的interrupt()方***中断线程的等待状态,会产生InterruptedException异常。
结果:
notify()与notifyAll的区别
notify()一次只能唤醒一个线程,如果有多个线程需要唤醒,notify()只能随机的唤醒其中的一个。notifyAll()可以唤醒所有的线程。
final static Object object=new Object(); public static void main(String[] args) throws InterruptedException { Thread thread01= new Thread(new Runnable() { @Override public void run() { synchronized (object) { System.out.println(Thread.currentThread().getName() + " 开始等待"); try { object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 等待结束"); } } }); Thread thread02= new Thread(new Runnable() { @Override public void run() { synchronized (object) { System.out.println(Thread.currentThread().getName() + " 开始等待"); try { object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 等待结束"); } } }); Thread thread03= new Thread(new Runnable() { @Override public void run() { synchronized (object) { System.out.println(Thread.currentThread().getName() + " 开始等待"); try { object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 等待结束"); } } }); Thread thread04= new Thread(new Runnable() { @Override public void run() { synchronized (object) { System.out.println(Thread.currentThread().getName() + " 开始唤醒"); object.notifyAll(); System.out.println(Thread.currentThread().getName() + " 唤醒结束"); } } }); thread01.start(); thread02.start(); thread03.start(); Thread.sleep(5000); thread04.start(); }
全部唤醒结果:
wait(long) 方法
如果在long时长内线程没有被唤醒,那么这个线程会自动唤醒。
通知过早
当线程等待唤醒之前就执行了唤醒操作,可能就会影响程序正常的工作流程。