• 并发编程(五)LockSupport


    并发编程(五)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

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

  • 相关阅读:
    Js通用验证
    C#实现马尔科夫模型例子
    C# 生成pdf文件客户端下载
    Js跨一级域名同步cookie
    C#数据库连接池 MySql SqlServer
    关于Oracle row_number() over()的简单使用
    开发中mybatis的一些常见问题记录
    Java通过图片url地址获取图片base64位字符串的两种方式
    基于apache httpclient的常用接口调用方法
    通过jcrop和canvas的画布功能完成对图片的截图功能与视频的截图功能实现
  • 原文地址:https://www.cnblogs.com/binarylei/p/10074774.html
Copyright © 2020-2023  润新知