java线程间通信之wait/notify实现
想一下,在没有等待/通知之前,如何实现线程间通信?
一般都是多个线程共享同一个变量,然后根据变量的变化决定相应操作。但是多线程获取共享变量值这个过程既耗时,又不能保证完全正确。
所以需要引入等待/通知机制。
方法wait()可以使当前执行代码的线程进入等待状态,wait()是object类的方法,在调用wait()前,线程必须获得该对象的对象级别锁,也就是只能在同步方法或同步方法块中执行该方法,否则会抛一个runtimeexception,IllegalMonitorStateException,运行时异常不需要try-cach。
方法notify()可以使当前对象中某个正在等待的线程变为继续执行,它和wait()方法的使用条件类似。有一点要注意,那就是在执行notify()方法后,当前线程并不会立马释放锁,而是要等到同步方法或同步代码块执行完,它才会释放锁。
在同步代码块中使用wait的总结:
1)同步代码块执行完,对象的锁就会自动释放。
2)同步代码块里出现异常导致线程终止,锁也会释放。
3)当线程调用wait呈等待状态时,调用此线程的interrupt方法,会报InterruptedException异常。
wait()还可以这样用wait(xxx).
当在使用wait/notify机制时,要注意不要提前notify,那样可能导致后面执行wait的线程永远不被唤醒。
实例生产者/消费者
最后来个示例,20个线程备份数据库,A-B-A-B。。。这样进行交叉备份,看代码
1 public class DBtools { 2 3 String flag = "A"; 4 5 synchronized public void backupA(){ 6 try { 7 while (flag.equals("B")) { 8 wait(); 9 } 10 System.out.println("备份数据到A库"); 11 Thread.sleep(1000); 12 flag = "B"; 13 notifyAll(); 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 } 18 synchronized public void backupB(){ 19 try { 20 while (flag.equals("A")) { 21 wait(); 22 } 23 System.out.println("备份数据到B库"); 24 Thread.sleep(1000); 25 flag = "A"; 26 notifyAll(); 27 } catch (InterruptedException e) { 28 e.printStackTrace(); 29 } 30 } 31 }
1 public class BackupA extends Thread { 2 private DBtools dBtools; 3 public BackupA(DBtools dBtools) { 4 this.dBtools = dBtools; 5 } 6 @Override 7 public void run() { 8 dBtools.backupA(); 9 } 10 }
1 public class BackupB extends Thread { 2 private DBtools dBtools; 3 public BackupB(DBtools dBtools) { 4 this.dBtools = dBtools; 5 } 6 @Override 7 public void run() { 8 dBtools.backupB(); 9 } 10 }
1 public class Run { 2 public static void main(String[] args) { 3 DBtools dBtools = new DBtools(); 4 for (int i = 0; i < 10; i++) { 5 BackupA backupA = new BackupA(dBtools); 6 BackupB backupB = new BackupB(dBtools); 7 backupA.start(); 8 backupB.start(); 9 } 10 } 11 }