想一下,在没有等待/通知之前,如何实现线程间通信?
一般都是多个线程共享同一个变量,然后根据变量的变化决定相应操作。但是多线程获取共享变量值这个过程既耗时,又不能保证完全正确。
所以需要引入等待/通知机制。
方法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 }