抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

摘要:本文学习了ThreadLocal的用法和原理。

环境

Windows 10 企业版 LTSC 21H2
Java 1.8

1 简介

LockSupport是用来创建锁和其他同步类的基本线程阻塞原语,在内部使用凭证的概念来实现阻塞和唤醒,每个线程都有一个凭证,只有1和0两个值,默认是0。

LockSupport中提供了两个方法:

  • park()方法会在凭证可用时执行,将凭证从1变成0,用于阻塞线程。
  • unpark()方法会在凭证不可用时执行,将凭证从0变成1,用于唤醒线程。

LockSupport中的方法调用的是Unsafe类中的native代码。

2 比较

比较三种阻塞唤醒线程的方式:

  • 使用Object的wait()方法和notify()方法:
    • 使用wait()方法阻塞线程,使用notify()方法唤醒线程。
    • 必须在synchronized代码块内部执行,否则抛出IllegalMonitorStateException。
    • 必须先执行wait()方法再执行notify()方法,否则线程会一直等待无法被唤醒。
  • 使用Condition的await()方法和signal()方法:
    • 使用await()方法阻塞线程,使用signal()方法唤醒线程。
    • 必须和Lock组队使用,否则抛出IllegalMonitorStateException。
    • 必须先执行await()方法再执行signal()方法,否则线程会一直等待无法被唤醒。
  • 使用LockSupport的park()方法和uppark()方法:
    • 使用park()方法阻塞线程,使用uppark()方法唤醒线程。
    • 不需要在任何代码块内执行,可以在任何地方执行。
    • 使用顺序无要求,即使先执行uppark()方法再执行park()方法,也能唤醒线程。

3 使用

示例:

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public static void main(String[] args) {
Thread a = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "进入");
LockSupport.park();
System.out.println(Thread.currentThread().getName() + "执行");
}, "a");
a.start();
Thread b = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "进入");
LockSupport.unpark(a);
System.out.println(Thread.currentThread().getName() + "执行");
}, "b");
b.start();
}

结果:

log
1
2
3
4
5
b进入
b执行
// 等待1s
a进入
a执行

4 总结

LockSuport是一个线程阻塞工具类,底层调用的Unsafe中的native代码,所有的方法都是静态方法,可以让线程在任意位置阻塞和唤醒。

两个方法:

  • 调用park()方法,将凭证从1变成0,立即返回并继续执行。如果凭证为0则会阻塞,直到unpark()方法将凭证从0变为1。
  • 调用unpark()方法,将凭证从0变成1,立即返回并继续执行,多次调用unpark()方法不会累加凭证。如果凭证为1则会阻塞,直到park()方法将凭证从1变为0。

评论