-
如何使用 wait + notify 实现通知机制?
1)Object 类的 wait 和 notify方法实现线程阻塞
* 首先,wait、notify 方法是针对对象的,调用任意对象的 wait 方法都将导致线程阻塞,阻塞的同时也将释放该对象的锁,相应地,调用任意对象的 notify 方法则将随机解除该对象阻塞的线程,但它需要重新获取改对象的锁,直到获取成功才能往下执行 * 其次,wait、notify 方法必须在 synchronized 块或方法中被调用,并且要保证同步块或方法的锁对象与调用 wait、notify 方法的对象是同一个,如此一来在调用 wait 之前当前线程就已经成功获取某对象的锁,执行 wait 阻塞后当前线程就将之前获取的对象锁释放。
我们先来看看wait和notify不用在synchronized代码块里边的报错示例:
public class WaitTest {
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();
System.out.println("wait之前的代码");
obj.wait();
System.out.println("wait之后的代码");
}
}
执行上边的这段代码会报错如下:
为什么会这样呢?
当一个线程需要调用对象的 wait()方法的时候,这个线程必须拥有该对象的锁,接着它就会释放这个对象锁并进入等待状态直到其他线程调用这个对象上的 notify()方法。同样的,当一个线程需要调用对象的 notify()方法时,它会释放这个对象的锁,以便其他在等待的线程就可以得到这个对象锁。由于所有的这些方法都需要线程持有对象的锁,这样就只能通过同步来实现,所以他们只能在同步方法或者同步块中被调用。
wait和notify代码示例:
LockTest代码
package threadtest.wait;
public class LockTest {
private Object obj = new Object();
public void waitTestMethod() throws InterruptedException {
synchronized (obj){
System.out.println(Thread.currentThread().getName()+"执行wait等待");
obj.wait();
System.out.println(Thread.currentThread().getName()+"唤醒wait运行");
}
}
public void notifyTestMethod() throws InterruptedException {
synchronized (obj){
System.out.println(Thread.currentThread().getName()+"执行notify前");
obj.notify();
System.out.println(Thread.currentThread().getName()+"执行notify后唤醒wait运行");
}
}
}
线程A代码
package threadtest.wait;
public class ThreadA implements Runnable{
private LockTest lockTest;
public ThreadA(LockTest lockTest) {
this.lockTest = lockTest;
}
@Override
public void run() {
try {
lockTest.waitTestMethod();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
线程B代码
package threadtest.wait;
public class ThreadB implements Runnable{
private LockTest lockTest;
public ThreadB(LockTest lockTest) {
this.lockTest = lockTest;
}
@Override
public void run() {
try {
lockTest.notifyTestMethod();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
执行main方法
package threadtest.wait;
public class TestThread {
public static void main(String[] args) {
LockTest lockTest = new LockTest();
Thread threadA = new Thread(new ThreadA(lockTest));
threadA.setName("threadA");
Thread threadB = new Thread(new ThreadB(lockTest));
threadB.setName("threadB");
threadA.start();
threadB.start();
}
}
代码运行后如图所示
解析上述代码:
1、线程A获取锁后,执行wait方法释放锁
2、线程b不会立即获取锁,因为线程A获取锁后线程B会进行等待,线程A执行wait方法释放锁后线程B获取锁,线程B执行notify方法后释放锁,唤醒线程A,线程进入就绪状态,获取cpu的执行权后继续执行代码