Java 线程间通信
2022-09-07 本文已影响0人
Tinyspot
1. 线程之间如何通信
- 共享内存(隐式通信)
- 消息传递(显式通信 wait / notify synchronized)
1.2 阻塞
- BLOCKED 和 WAITING 的线程都处于阻塞状态,不占用 CPU 时间片
- BLOCKED 线程会在 Owner 线程释放锁时唤醒
- WAITING 线程会在 Owner 线程调用 notify 或 notifyAll 时唤醒,但唤醒后并不意味着立刻获得锁,仍需进入 EntryList 重新竞争
2. wait() / notify() / notifyAll()
- 都是 Object 对象的方法,必须获得此对象的锁,才能调用这些方法
- obj.wait()
- obj.notify() 唤醒 obj 上任意一个线程
- obj.notifyAll() 唤醒 obj 上所有正在 WaitSet 等待的线程
2.1 wait()
public class Demo {
// 声明为 final, 表示引用不可变,若引用变了,synchronized 锁的就是不同对象
static final Object obj = new Object();
public static void main(String[] args) throws InterruptedException {
obj.wait();
}
}
运行会抛异常 Exception in thread "main" java.lang.IllegalMonitorStateException
,因为此时并未获得锁
public class Demo {
static final Object obj = new Object();
public static void main(String[] args) throws InterruptedException {
synchronized (obj) {
obj.wait();
}
}
}
使用 synchronized 先获得锁,成为该锁的 owner, 然后再调用 wait()
2.2 wait(long n)
有时限的等待,到 n 毫秒后结束等待,或被 notify()
public final void wait() throws InterruptedException {
wait(0);
}
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException {}
示例
static final Object obj = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (obj) {
log.debug("start...");
try {
obj.wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("do something...");
}
}).start();
}
2.3 notify() / notifyAll()
@Slf4j
public class Demo {
static final Object obj = new Object();
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
synchronized (obj) {
log.debug("run...");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("do something...");
}
}).start();
new Thread(() -> {
synchronized (obj) {
log.debug("run...");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("do something...");
}
}).start();
TimeUnit.SECONDS.sleep(1);
synchronized (obj) {
// obj.notify();
obj.notifyAll();
}
}
}
3. wait() vs sleep()
- wait(), notify() 和 notifyAll() 被定义在 Object 类,而 sleep() 定义在 Thread 类
- wait() 要在同步代码块内使用(要先获取对象锁,和 synchronized 一起用),而 sleep() 不需要
- wait() 在等待的时候会释放对象锁,而 sleep() 在睡眠的同时,不会释放对象锁
public class Thread implements Runnable {
public static native void sleep(long millis) throws InterruptedException;
}
public class Object {
public final native void wait(long timeout) throws InterruptedException;
}
3.1 验证 sleep() 不释放锁
@Slf4j
public class Demo {
static final Object obj = new Object();
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
synchronized (obj) {
log.debug("start...");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("do something...");
}
}).start();
TimeUnit.SECONDS.sleep(1);
// main 线程想获取锁,并执行逻辑
synchronized (obj) {
log.debug("run...");
}
}
}
执行结果
22:16:16.687 [Thread-0] DEBUG com.example.concrete.Demo - start...
22:16:19.691 [Thread-0] DEBUG com.example.concrete.Demo - do something...
22:16:19.691 [main] DEBUG com.example.concrete.Demo - run...