多线程如何进行线程间的通信
测试代码:
// 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()方法可以实现线程件的通信。