zoukankan      html  css  js  c++  java
  • 并发编程(五)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

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

  • 相关阅读:
    【现代程序设计】【Homework01】
    Apache 关于 mod_rewrite 遇到 %2F或%5C (正反斜杠)等特殊符号导致URL重写失效出现404的问题
    PHP 使用CURL库IP欺骗,隐藏真实客户端IP
    php客服聊天回话系统,长连接加ajax轮询实现
    Which PHP version do I choose
    批量操作,向后台传数组
    angularjs的directive详解
    table中表头不动,表体产生滚动条
    3263232
    forEach、for+i、map的用法及区别
  • 原文地址:https://www.cnblogs.com/binarylei/p/10074774.html
Copyright © 2011-2022 走看看