并发编程(五)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. uva-193-图染色-枚举

    题意:n个节点,可用描成黑色或者白色,黑节点和黑节点不能相连,问最多描出多少黑节点 #include <iostream> #include <stdio.h> #includ ...

  2. Java-IntegerCache

    Integer类里面有一个私有的静态内部类IntegerCache类加载时,有一段静态块代码,如下 static final int low = -128; static final int high ...

  3. 最近玩的centos7.3用的防火墙转载

    CentOS 7 firewalld使用简介 1.firewalld简介 firewalld是centos7的一大特性,最大的好处有两个:支持动态更新,不用重启服务:第二个就是加入了防火墙的“zone ...

  4. datasnap 如何监控客户端的连接情况

    如果客户端是TCP/IP是短连接的情况就没有必要了. type pClientConns = ^TClientConns; // 客户连接 TClientConns = record clientid ...

  5. salt常用模块及API

    saltstack提供了非常丰富的功能模块,涉及操作系统的基础功能,常用工具支持等,更多模块信息见官网模块介绍:https://docs.saltstack.com/en/latest/ref/mod ...

  6. Java 枚举那点事

    目录 最近有需求,想存自定义的枚举值,比如 HOTLINE("Hotline") 我想存 Hotline 于是研究了一下Java的枚举问题 如下数据库的Entity (贫血模型哈) ...

  7. iis配置asp.net常见验证失败问题解决方案

    很多朋友在用IIS6架网站的时候遇到不少问题,而这些问题有些在过去的IIS5里面就遇到过,有些是新出来的,俺忙活了一下午,做 了很多次试验,结合以前的排错经验,做出了这个总结,希望能给大家帮上忙:) ...

  8. C语言高级-结构,共用体,文件,链表

    C语言结构 标准声明方式 struct student{        int age;        char sex;    }; 这个可以在main函数中定义:  struct student ...

  9. Conductor Server

    安装 要求 数据库:Dynomite               https://github.com/Netflix/dynomite 索引后端: Elasticsearch 2.x    http ...

  10. DEXSeq

    1)Introduction DEXSeq是一种在多个比较RNA-seq实验中,检验差异外显子使用情况的方法. 通过差异外显子使用(DEU),我们指的是由实验条件引起的外显子相对使用的变化. 外显子的 ...