synchronized 结合 java.lang.Object
对象中的wait()
、notify()
、notifyAll()
。
线程A
public class ThreadA extends Thread{
private Object lock;
public ThreadA(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock){
System.out.println("ThreadA---start");
try {
//实现线程阻塞
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("ThreadA---end");
}
}
}
线程B
public class ThreadB extends Thread {
private Object lock;
public ThreadB(Object lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
System.out.println("ThreadB---start");
//实现线程的唤醒
lock.notify();
System.out.println("ThreadB---end");
}
}
}
测试
public class WaitDemo {
public static void main(String[] args) {
Object lock = new Object();
ThreadA threadA = new ThreadA(lock);
threadA.start();
ThreadB threadB = new ThreadB(lock);
threadB.start();
}
}
运行输出
ThreadA---start
ThreadB---start
ThreadB---end
ThreadA---end
ThreadA阻塞挂起,ThreadB唤醒,ThreadA被唤醒。
上面这段代码我们会发现被阻塞的线程什么时候被唤醒,取决于获得锁的线程什么时候执行完同步代码块并且释放锁。
那怎么做到显示控制呢?我们就需要借 助 一 个 信 号机 制 :在 Object 对 象 中 ,提 供 了wait/notify/notifyall,可以用于控制线程的状态
CPU
资源并进入等待状态。JVM
唤醒某个竞争该对象锁的线程 X。线程 A 同步代码块执行结束并且释放了锁之后,线程 X 直接获得对象锁权限,其他竞争线程继续等待(即使线程 X 同步完毕,释放对象锁,其他竞争线程仍然等待,直至有新的 notify ,notifyAll 被调用)。需要注意的是:
三个方法都必须在 synchronized 同步关键字所限定的作用域中调用 ,否则会报错
java.lang.IllegalMonitorStateException
意思是因为没有同步,所以线程对对象锁的状态是不确定的,不能调用这些方法。另外,通过同步机制来确保线程从 wait 方法返回时能够感知到感知到 notify 线程对变量做出的修改waity /notify 。
注意两个队列: