并发编程(五)LockSupport

LockSupport 提供 park() 和 unpark() 方法实现阻塞线程和解除线程阻塞,实现的阻塞和解除阻塞是基于“许可(permit)”作为关联,permit 相当于一个信号量(0,1),默认是0。 线程之间不再需要一个 Object 或者其它变量来存储状态,不再需要关心对方的状态。

一、LockSupport API

(1) pack

方法 说明
park() 挂起当前线程
park(Object blocker) 挂起当前线程
parkNanos(long nanos) 指定挂起时间(相对于当前的时间),时间到后自动被唤醒
parkNanos(Object blocker, long nanos) 指定挂起时间(相对于当前的时间)
parkUntil(long deadline) 指定挂起时间(绝对时间),时间到后自动被唤醒
parkUntil(Object blocker, long deadline) 指定挂起时间(绝对时间),时间到后自动被唤醒

从上面表格可以看出,park 支持 blocker 对象作为参数,该字段是 Thread 类,专门为 LockSupport 而设计的。此 blocker 对象在线程受阻塞时被记录,这样监视工具和诊断工具就可以确定线程受阻塞的原因。建议最好使用这些带 blocker 的方法版本,而不是不带 blocker 参数的方法。

public static void park() {
UNSAFE.park(false, 0L);
}

(2) unpark

设置线程许可为可用。

  • 如果线程当前已经被 pack 挂起,那么这个线程将会被唤醒。
  • 如果线程当前没有被挂起,那么下次调用 pack 不会挂起线程。
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}

二、LockSupport 使用

(1) 先park后unpark

public void test1() throws Exception {
Thread mainThread = Thread.currentThread();
Thread thread = new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("before unpark, " + LockSupport.getBlocker(mainThread));
LockSupport.unpark(mainThread);
System.out.println("after unpark, " + LockSupport.getBlocker(mainThread));
});
thread.start();
System.out.println("before park");
// 等待获取许可
LockSupport.park("Park");
System.out.println("after park");
}

结果:

before park
before unpark, Park
after park
after unpark, null

(2) 先unpark后unpark

先执行 unpark,在调用 park,直接就没被阻塞, 因此 park/unpark 相比 wait/notify 更加的灵活

public void test2() throws Exception {
Thread mainThread = Thread.currentThread();
Thread thread = new Thread(() -> {
System.out.println("before unpark, " + LockSupport.getBlocker(mainThread));
LockSupport.unpark(mainThread);
System.out.println("after unpark, " + LockSupport.getBlocker(mainThread));
});
thread.start(); TimeUnit.SECONDS.sleep(1);
System.out.println("before park");
// 等待获取许可
LockSupport.park("Park");
System.out.println("after park");
}

(2) park与interrupt

public void test3() throws Exception {
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().isInterrupted()); // false
LockSupport.park();
System.out.println(Thread.currentThread().isInterrupted()); // true
});
thread.start(); TimeUnit.SECONDS.sleep(1);
thread.interrupt();
System.in.read();
}

简而言之:

  1. 实现机制和 wait/notify 有所不同,面向的是线程
  2. 不需要依赖监视器
  3. 与 wait/notify 没有交集
  4. 使用起来方便灵活

参考:

  1. 《LockSupport解析与使用》:https://blog.csdn.net/secsf/article/details/78560013

每天用心记录一点点。内容也许不重要,但习惯很重要!

并发编程(五)LockSupport的更多相关文章

  1. 【Java并发编程五】信号量

    一.概述 技术信号量用来控制能够同时访问某特定资源的活动的数量,或者同时执行某一给定操作的数据.计数信号量可以用来实现资源池或者给一个容器限定边界. 信号量维护了一个许可集,许可的初始量通过构造函数传 ...

  2. Java并发编程 (五) 线程安全性

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.安全发布对象-发布与逸出 1.发布与逸出定义 发布对象 : 使一个对象能够被当前范围之外的代码所使用 ...

  3. 【Java并发编程实战】----- AQS(三):阻塞、唤醒:LockSupport

    在上篇博客([Java并发编程实战]----- AQS(二):获取锁.释放锁)中提到,当一个线程加入到CLH队列中时,如果不是头节点是需要判断该节点是否需要挂起:在释放锁后,需要唤醒该线程的继任节点 ...

  4. 并发编程实践五:ReentrantLock

    ReentrantLock是一个可重入的相互排斥锁,实现了接口Lock,和synchronized相比,它们提供了同样的功能.但ReentrantLock使用更灵活.功能更强大,也更复杂.这篇文章将为 ...

  5. 并发编程(十五)——定时器 ScheduledThreadPoolExecutor 实现原理与源码深度解析

    在上一篇线程池的文章<并发编程(十一)—— Java 线程池 实现原理与源码深度解析(一)>中从ThreadPoolExecutor源码分析了其运行机制.限于篇幅,留下了Scheduled ...

  6. [Java并发编程(五)] Java volatile 的实现原理

    [Java并发编程(五)] Java volatile 的实现原理 简介 在多线程并发编程中 synchronized 和 volatile 都扮演着重要的角色,volatile 是轻量级的 sync ...

  7. java高并发编程(五)线程池

    摘自马士兵java并发编程 一.认识Executor.ExecutorService.Callable.Executors /** * 认识Executor */ package yxxy.c_026 ...

  8. Java并发编程原理与实战五:创建线程的多种方式

    一.继承Thread类 public class Demo1 extends Thread { public Demo1(String name) { super(name); } @Override ...

  9. 并发编程概述 委托(delegate) 事件(event) .net core 2.0 event bus 一个简单的基于内存事件总线实现 .net core 基于NPOI 的excel导出类,支持自定义导出哪些字段 基于Ace Admin 的菜单栏实现 第五节:SignalR大杂烩(与MVC融合、全局的几个配置、跨域的应用、C/S程序充当Client和Server)

    并发编程概述   前言 说实话,在我软件开发的头两年几乎不考虑并发编程,请求与响应把业务逻辑尽快完成一个星期的任务能两天完成绝不拖三天(剩下时间各种浪),根本不会考虑性能问题(能接受范围内).但随着工 ...

随机推荐

  1. 1.scrapyd部署相关问题

    部署scrapy爬虫项目到6800上 启动scrapyd 出现问题 1: scrapyd-deloy -l  未找到相关命令 scrapyd-deploy -l 可以看到当前部署的爬虫项目,但是当我输 ...

  2. OpenACC kernels

    ▶ 使用 kernels 导语并行化 for 循环 ● 一重循环 #include <stdio.h> #include <time.h> #include <opena ...

  3. scala.XML处理

    XML scala提供了对xml字面量的内建支持,我们可以很容易的在程序代码中生成xml片段, scala类库也包含了对xml常用处理的支持 有时候scala会错误识别出xml字面量 如x < ...

  4. leetcode237

    /** * Definition for singly-linked list. * public class ListNode { * public int val; * public ListNo ...

  5. 7. mybatis实战教程(mybatis in action)之八:mybatis 动态sql语句

    转自:http://www.kyjszj.com/htzq/79.html 1. if 语句 (简单的条件判断) 2. choose (when,otherwize) ,相当于java 语言中的 sw ...

  6. jquery checkbox

    $(document).ready(function() { var $cr = $("#cr"); var cr = $cr[0]; $cr.click(function() { ...

  7. UITableView cell 半透明效果,改变cell高度时背景不闪的解决方法

    如果直接指定cell.backgroundColor = = [UIColor colorWithRed:255.0/255.0 green:255.0/255.0 blue:255.0/255.0 ...

  8. Mybatis知识(5)

    1. #{} 与${}的区别 #{}解释为 JDBC prepared statement 的一个参数标记,而${}解释为字符串替换.比如:我们不能在表名的位置使用参数标记,也不能在列名的位置使用参数 ...

  9. 快速可靠网络传输协议 KCP(转)

    KCP 是一个快速可靠协议,能以比 TCP浪费10%-20%的带宽的代价,换取平均延迟降低30%-40%,且最大延迟降低三倍的传输效果.纯算法实现,并不负责底层协议(如UDP)的收发,需要使用者自己定 ...

  10. install命令

    install 1.作用 install命令的作用是安装或升级软件或备份数据,它的使用权限是所有用户. 2.格式 (1)install [选项]... 来源 目的地 (2)install [选项].. ...