线程通信
线程是系统的个体,线程想要构成一个整体,就需要线程间通信。使用wait和notify可以实现线程间通信。
wait和notify
wait和notify是Object的方法。他们都涉及到锁相关操作
- wait:等待对象的同步锁,需要获得该对象的同步锁才可以调用这个方法,否则编译可以通过,但运行时会收到一个异常:IllegalMonitorStateException。所以只能在同步方法或者同步块中调用wait方法
调用任意对象的 wait() 方法导致该线程阻塞,该线程不可继续执行,并且该对象上的锁被释放。
notify:唤醒在等待该对象同步锁的线程(只唤醒一个,如果有多个在等待),注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。同样,也只能在同步方法或者同步块中调用notify方法
调用任意对象的notify()方法则导致因调用该对象的 wait()方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。
notifyAll:唤醒所有等待的线程,注意唤醒的是notify之前wait的线程,对于notify之后的wait线程是没有效果的。
总之:
1. wait使线程等待(释放锁给调用notify的线程,等待锁),notify使停止线程运行。
2. 两者都要在同步方法中运行。
3. notify方法执行后不会立即释放锁。只是让线程进入就绪状态。等notify所在的同步方法执行完之后才释放锁。
4. notify一次只能随机唤醒一个线程。当有多个需要唤醒时,可调用notifyAll
5. wait(long)可以自动唤醒。
示例1 不在同步方法中调用wait
public class WaitTest {
public static void main(String[] args){
String lock=new String();
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出异常:
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at com.thread3.communicate.WaitTest.main(WaitTest.java:7)
改为在同步方法中调用:
public class WaitTest {
public static void main(String[] args) {
String lock = new String();
try {
synchronized (lock) {
lock.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
示例2 wait和notify
class MyThreadA extends Thread {
private Object lock;
public MyThreadA(Object lock) {
this.lock = lock;
}
@Override
public void run() {
try {
System.out.println("ThreadA 1");
synchronized (lock) {
System.out.println("ThreadA 2");//打印这个之后会进行等待
lock.wait();
System.out.println("ThreadA 3");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class MyThreadB extends Thread {
private Object lock;
public MyThreadB(Object lock) {
this.lock = lock;
}
@Override
public void run() {
System.out.println("ThreadB 1");
synchronized (lock) {
System.out.println("ThreadB 2");
lock.notify();
System.out.println("ThreadB 3");
}
}
}
public class WaitNotifyTest {
public static void main(String[] args) throws InterruptedException {
String lock = new String();
MyThreadA threadA=new MyThreadA(lock);
MyThreadB threadB=new MyThreadB(lock);
threadA.start();
Thread.sleep(2000);
threadB.start();
}
}
输出结果:
ThreadA 1
ThreadA 2
ThreadB 1
ThreadB 2
ThreadB 3 //这个比下面先输出,可以看出调用notify不会立即释放锁,让线程A立即执行。
ThreadA 3
interrupt遇到wait方法
当线程处于wait状态时,调用线程的interrupt,会跑出InterruptedException异常。
class MyThreadAA extends Thread {
private Object lock;
public MyThreadAA(Object lock) {
this.lock = lock;
}
@Override
public void run() {
try {
System.out.println("MyThreadAA 1");
synchronized (lock) {
System.out.println("MyThreadAA 2");//打印这个之后会进行等待
lock.wait();
System.out.println("MyThreadAA 3");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class WaitInterruptExpTest {
public static void main(String[] args) throws InterruptedException {
String lock = new String();
MyThreadAA threadA=new MyThreadAA(lock);
threadA.start();
Thread.sleep(2000);
threadA.interrupt();
}
}
输出:
MyThreadAA 1
MyThreadAA 2
java.lang.InterruptedException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at com.thread3.communicate.MyThreadAA.run(WaitInterruptExpTest.java:16)