线程是系统运行中的一个独立的子任务,这些子任务经过程序的处理构成了一个完整的任务,而这些子任务之间能够相互通信是构成完整任务不可缺少的一部分。使用多线程通信,可以在执行程序的时候大大提高CPU的使用效率。
那么多线程通信的方式有哪些呢,现在由基本的开始说起。
wait/notify方法(使用等待/通知机制实现多线程通信)
wait()方法是Object类的方法,它的作用是使当前正在执行代码的线程进行等待,并释放对象锁,并停在wait()代码处,直到接到通知才继续执行或是中断。
执行wait()方法前:线程必须先获取对象锁,否则会抛出异常IllegalMonitorStateException。
执行wait()方法后:线程释放对象锁。
因此wait()方法要写在同步方法或是同步代码块中。
notify()方法同样是Object类的方法,它的作用是唤醒正在等待(wait状态)的线程(随机唤醒一个等待线程),需要注意的是,当前执行notify()的方法的线程执行完notify()方法后不会马上释放对象锁,因此被唤醒的等待线程也不会马上获取该对象锁,只有当执行notify()方法的线程执行完所在的同步代码块或是同步方法后,才会释放对象锁。
单个线程等待--单个线程唤醒(注意释放锁的时机)
public class TestThreadObject {
public void testWaitThread(Object obj){
synchronized (obj){
try {
System.out.println("开始执行wait()方法");
obj.wait();
System.out.println("结束执行wait()方法");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void testNofityThread(Object obj){
synchronized (obj){
try {
System.out.println("开始执行notify()方法");
obj.notify();
System.out.println("结束执行notify()方法");
Thread.sleep(1000);
System.out.println("注意注意,notify()方法执行完毕了,还在synchronized里面,但是我还没释放对象锁");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("再次注意注意,notify()方法执行完毕后,不在synchronized里面,你猜我有没有释放对象锁");
}
}
public class ThreadTestWait extends Thread {
private Object obj;
public ThreadTestWait(Object obj){
super();
this.obj = obj;
}
@Override
public void run(){
TestThreadObject testThreadObject = new TestThreadObject();
testThreadObject.testWaitThread(obj);
}
}
public class ThreadTestNotify extends Thread {
private Object obj;
public ThreadTestNotify(Object obj){
super();
this.obj = obj;
}
@Override
public void run(){
TestThreadObject testThreadObject = new TestThreadObject();
testThreadObject.testNofityThread(obj);
}
}
public class Test1 {
public static void main(String[] args){
Object obj = new Object();
ThreadTestA threadTestA = new ThreadTestA(obj);
threadTestA.start();
ThreadTestB threadTestB = new ThreadTestB(obj);
threadTestB.start();
}
}
通过代码可以看出notify()方法执行完成后并不会马上释放锁,只有在执行完同步代码块或是同步方法后才释放锁。
唤醒所有等待线程(notifyAll()方法)
如果使用notify()方法的话,每次只能唤醒一个等待线程,当需要唤醒所有等待线程的时候,可以使用notifyAll()方法,唤醒是随机的。ThreadTestWait,ThreadTestNotify类不做改动,调整TestThreadObject类的输出内容便于观察。
public class TestThreadObject {
public void testWaitThread(Object obj){
synchronized (obj){
try {
System.out.println("线程" + Thread.currentThread().getName() + ":" + "开始执行wait()方法");
obj.wait();
System.out.println("线程" + Thread.currentThread().getName() + ":" + "结束执行wait()方法");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void testNofityThread(Object obj){
synchronized (obj){
System.out.println("线程" + Thread.currentThread().getName() + ":" + "开始执行notifyAll()方法");
obj.notifyAll();
System.out.println("线程" + Thread.currentThread().getName() + ":" + "结束执行notifyAll()方法");
}
}
}
public class Test1 {
public static void main(String[] args){
Object obj = new Object();
ThreadTestWait waitThread = null;
for(int i = 0; i < 5; i++){
waitThread = new ThreadTestWait(obj);
waitThread.setName("waitThread-" + i);
waitThread.start();
}
ThreadTestNotify notifyThread = new ThreadTestNotify(obj);
notifyThread.setName("notifyThread");
notifyThread.start();
}
}
所有等待线程成功被唤醒。
注意:唤醒等待线程的时候可能会出现以下情况
唤醒过早,造成程序逻辑错误。