Java LockSupport

Java LockSupport

Java LockSupport

简介

查看JavaDoc

阅读以上内容了解到LockSupport引入一个“许可证”的概念,并且每个使用LockSupport的每个线程都会关联一个“许可证”
这个“许可证”类似“锁计数器”但是与“锁计数器”不同,“许可证”不可累积,最多只有一个。言外之意就是“许可证”只能有两个值“0”和“1”。

知道两个关键的方法LockSupport#park()LockSupport#unpark(),这两个方法是对线程等待唤醒wait/notify)机制的加强。

加强在哪?

要知道加强在哪首先要复习下synchronizedLock的线程等待唤醒使用方法。

synchronized

使用java.lang.Object#wait()/java.lang.Object#notify来实现线程的等待与唤醒。

  • 使用waitnotify必须在synchronized里使用同一个锁对象,若移除同步代码块(synchronized)则会出现IllegalMonitorStateException异常。
  • waitnotify执行顺序必须先waitnotify,否则等待钟的线程将无法唤醒。

Lock

使用ConditionCondition#await()Condition#signal方法来实现线程的等待与唤醒。

  • 使用Lock#newCondition获得Condition对象
  • 使用awaitsignal必须在同一锁对象中使用
  • awaitsignal执行顺序必须先awaitsignal,否则等待钟的线程将无法唤醒。

小结

传统的synchronizedLock实现等待唤醒的约束:

  • 线程先要获得并持有锁,必须在锁块(synchronizedLock)中。
  • 必须要先等待后唤醒,线程才能够被唤醒。

LockSupport

LockSupport类使用了一种名为“Permit”(许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个“Permit”,并且只有两个值“0”和“1”,默认为“0”
可以把“Permit”看作一种(0,1)信号量(Semaphore),但与“Semaphore”不同的是“Permit”的累加上限是1。

park(等待)

除非许可证可用,否则禁用当前线程以进行线程调度。

unpark(唤醒)

如果给定线程尚不可用,则为其提供许可。

实战

final Thread lockSupportThread1 = new Thread(() -> {
    System.out.println(Thread.currentThread().getName() + "\t in");
    System.out.println(Thread.currentThread().getName() + "\t do park");
    LockSupport.park();
    System.out.println(Thread.currentThread().getName() + "\t done");
}, "lockSupportThread1");

lockSupportThread1.start();

// 保证线程执行顺序,主线程等待1s
TimeUnit.SECONDS.sleep(1);

final Thread lockSupportThread2 = new Thread(() -> {
    System.out.println(Thread.currentThread().getName() + "\t in");
    System.out.println(Thread.currentThread().getName() + "\t do unpark");
    LockSupport.unpark(lockSupportThread1);
    System.out.println(Thread.currentThread().getName() + "\t done");
}, "lockSupportThread2");

lockSupportThread2.start();

控制台输出:

lockSupportThread1 in
lockSupportThread1 do park
lockSupportThread2 in
lockSupportThread2 do unpark
lockSupportThread2 done
lockSupportThread1 done

总结

  • LockSupport提供parkunpark方法实现线程的阻塞和解除线程阻塞。
  • 每个使用LockSupport的线程都有一个“凭证”,值只能为“0”或“1”,默认为“0”。
  • 调用一次unpark会增加一次“凭证”的值,只能由“0”变为“1”,调用一次park则会消费“凭证”,多次调用unpark“凭证”的值也只会为“1”。
  • parkunpark没有区分调用顺序,只需要注意“凭证”的值。
  • 不需要锁块
# Java  基础 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×