线程等待和唤醒的三种方式
# 线程等待和唤醒的三种方式
# 1. wait¬ify
使用Object种的wait()方法让线程等待,使用Object中的notify()方法唤醒线程。
public class LockSupportDemo {
static Object objectLock = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (objectLock) {
System.out.println(Thread.currentThread().getName() + "\t" + "---come in!");
objectLock.wait();
System.out.println(Thread.currentThread().getName() + "\t" + "---被唤醒!");
}
}, "A").start();
new Thread(() -> {
synchronized (objectLock) {
objectLock.notify();
System.out.println(Thread.currentThread().getName() + "\t" + "---通知!");
}
}, "B").start();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
注意:
wait 和 notify 不能脱离 synchronized 代码块,会出现
java.lang.IllegalMonitorStateException
异常先 notify 再 wait,notify 就起不到任何效果。必须要先等待后唤醒,线程才能被唤醒。
# 2 await&signal
使用JUC包中的 Condition 的 await()
方法让线程等待,使用 signal()
方法唤醒线程。
public class LockSupportDemo {
static Lock lock = new ReentrantLock();
static Condition condition = lock.newCondition();
public static void main(String[] args) {
new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "\t" + "---come in!");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t" + "---被唤醒!");
} finally {
lock.unlock();
}
}, "A").start();
new Thread(() -> {
lock.lock();
try {
condition.signal();
System.out.println(Thread.currentThread().getName() + "\t" + "---通知!");
} finally {
lock.unlock();
}
}, "B").start();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
注意:
condition.await()
和condition.signal()
要与成对的lock()
与unlock()
使用,否则会报java.lang.IllegalMonitorStateException
异常- 先 signal 再 await,signal 不起作用。必须要先等待后唤醒,线程才能被唤醒。
# 3 park&unpark
LockSupport 类可以阻塞当前线程以及缓存指定被阻塞的线程。
public class LockSupportDemo {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t" + "---come in!");
LockSupport.park(); // 阻塞,等待通知放行,它需要许可证
System.out.println(Thread.currentThread().getName() + "\t" + "---被唤醒!");
}, "A");
t1.start();
Thread t2 = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "\t" + "---通知!");
LockSupport.unpark(t1);
}, "B");
t2.start();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
注意:
- 与前面相比,不需要锁块。
- 可以先 unpark 再 park。先执行
unpark()
会导致park()
方法形同虚设。
编辑 (opens new window)
上次更新: 2023/08/20, 21:21:52