LockSupport工具
# LockSupport工具
# LockSupport介绍
LockSupport是用来创建锁和其他同步类的基本线程阻塞原语,是一个线程阻塞工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞,阻塞之后也有对应的唤醒方法。归根结底,LockSupport调用的Unsafe中的native代码。
LockSupport中的park()
和unpark()
的作用分别是阻塞线程和解除阻塞线程。
LockSupport和每个使用它的线程都有一个许可(permit)关联,permit相当于1,0开关,默认是0。可以把许可看成是一种(0, 1)信号量(Semaphore),但与Semaphore不同的是,许可的累加上限是1。
调用unpark就加1;调用一次park就会消费一个permit,也就是将1变成0,同时park立刻返回。如果再次调用park会阻塞,因为permit变为零会阻塞在这里,直到permit变为1。permit最大值为1,重复调用也不会累加。
LockSupport.park底层:
public static void park() {
UNSAFE.park(false, 0L);
}
1
2
3
2
3
LockSupport.unpark底层:
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
1
2
3
4
2
3
4
# 三种让线程等待和唤醒的方法?
⭐ 1 使用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 使用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 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