多线程如何进行线程间的通信
测试代码:
// class Service public class Service { public void testMethod(Object lock) { try{ synchronized (lock) { System.out.println("begin wait() ThreadName=" + Thread.currentThread().getName()); lock.wait(); System.out.println("end wait() ThreadName=" + Thread.currentThread().getName()); } } catch(InterruptedException e) { e.printStackTrace(); } } } // class ThreadA public class ThreadA extends Thread{ private Object lock; public ThreadA(Object lock) { this.lock = lock; } @Override public void run() { Service s = new Service(); s.testMethod(lock); } } // class ThreadB public class ThreadB extends Thread{ private Object lock; public ThreadB(Object lock) { this.lock = lock; } @Override public void run() { Service s = new Service(); s.testMethod(lock); } } // class ThreadC public class ThreadC extends Thread{ private Object lock; public ThreadC(Object lock) { this.lock = lock; } @Override public void run() { Service s = new Service(); s.testMethod(lock); } } // class NotifyThread public class NotifyThread extends Thread{ private Object lock; public NotifyThread(Object lock) { this.lock = lock; } @Override public void run() { synchronized (lock) { lock.notify(); // lock.notify(); // lock.notify(); // lock.notify(); // lock.notifyAll(); } } } // class Main public class Main { public static void main(String[] args) { service(); } private static void service() { try{ Object lock = new Object(); ThreadA ta = new ThreadA(lock); ta.start(); ThreadB tb = new ThreadB(lock); tb.start(); ThreadC tc = new ThreadC(lock); tc.start(); Thread.sleep(3000); // 主线程睡眠3秒钟 NotifyThread notifyThread = new NotifyThread(lock); notifyThread.start(); } catch(InterruptedException e) { e.printStackTrace(); } } }输出结果(程序还在执行状态,并没有退出,因为还有两个线程处于等待状态):
begin wait() ThreadName=Thread-0 begin wait() ThreadName=Thread-1 begin wait() ThreadName=Thread-2 end wait() ThreadName=Thread-0从以上输出中我们可以得知Thread-0首先获得了lock对象的对象锁,然后执行到lock.wait()后,Thread-0线程进入等待状态并释放了lock对象的对象锁、然后是Thread-1、Thread-2线程依次执行Thread-0的步骤。最后三个线程均进入等待状态并将lock对象的对象锁释放掉。主线程在等待了三秒后创建了notifyThread对象并新创建了一个线程,notifyThread线程获取lock对象的对象锁后执行lock.notify()方法随机唤醒三个等待线程中的一个(从打印结果看出随机唤醒的是Thread-0),被唤醒的线程继续执行lock.wait()后续代码,直至该线程的任务执行完毕。
结论:notify一次只能随机唤醒一个在等待的线程,如果存在多个等待线程,其他没被唤醒的线程会继续等待下去。
将NotifyThread的run方法内的lock.notify()全部解开注释,如下:
@Override public void run() { synchronized (lock) { lock.notify(); lock.notify(); lock.notify(); lock.notify(); // lock.notifyAll(); } }执行后的输出结果:
begin wait() ThreadName=Thread-0 begin wait() ThreadName=Thread-1 begin wait() ThreadName=Thread-2 end wait() ThreadName=Thread-0 end wait() ThreadName=Thread-2 end wait() ThreadName=Thread-1从以上输出结果可以看出,虽然执行了四次lock.notify()方法,但是只有三个线程处于等待状态,多次执行lock.notify()会被系统自动忽略。每次执行完lock.notify()方法后都会随机唤醒一个处于等待状态的线程。
我们将NotifyThread的run方法内的lock.notify();方法全部注释掉,解开lock.notifyAll();的注释代码,如下所示:
@Override public void run() { synchronized (lock) { // lock.notify(); // lock.notify(); // lock.notify(); // lock.notify(); lock.notifyAll(); } }再次执行后输出如下:
begin wait() ThreadName=Thread-0 begin wait() ThreadName=Thread-2 begin wait() ThreadName=Thread-1 end wait() ThreadName=Thread-1 end wait() ThreadName=Thread-2 end wait() ThreadName=Thread-0从以上结果可以看出,lock.notifyAll()方法会将所有处于等待的线程全部唤醒,也就不需要去关心有多少线程处于等待状态了。
通过wait()和notify(),notifyAll()方法可以实现线程件的通信。