zoukankan      html  css  js  c++  java
  • LockSupport学习

    LockSupport工具类定义了一组的公共静态方法,这些方法提供了最基本的线程阻塞和唤醒功能。Java锁和同步器框架的核心工具类AQS:AbstractQueueSynchronizer,就是通过调用LockSupport.park()和LockSupport.unpark()实现线程的阻塞和唤醒。

    LockSupport很类似于二元信号量(只有1个许可证可供使用),如果这个许可证还没有被占用,当前线程获取许可并继续执行。如果许可已经被占用,当前线程阻塞,等待获取许可。但是这个许可是不能叠加的,“许可”是一次性的。

    比如线程B连续调用了三次unpark函数,当前线程A调用park函数就使用掉这个“许可”,如果线程A再次调用park,则进入等待状态。

    注意:unpark函数可以先于park调用。比如线程B调用unpark函数,给线程A发了一个“许可”,那么当线程A调用park时,它发现已经有“许可”了,那么它会马上再继续运行。

    park和unpark的灵活之处

    上面已经提到了,unpark函数可以先于park调用,这个正是它们的灵活之处。

    一个线程它有可能在别的线程unpark之前,或者之后,或者同时调用park,那么因为park的特性,它可以不用担心自己的park的时序问题,否则,如果park必须要在unpark之前,那么给编程带来很大的麻烦!!

    考虑一下,两个线程同步,要如何处理?

    在Java5里是用wait/notify/notifyAll来同步的。wait和notify机制有个很蛋疼的地方是,比如线程B要用notify通知线程A,那么线程B要确保线程A已经在wait调用上等待了,否则线程A可能永远都在等待。编程的时候就会很蛋疼。

    另外,是调用notify,还是notifyALL?

    notify只会唤醒一个线程,如果错误地有两个线程在同一个对象上wait等待,那么又悲剧了。为了安全起见,貌似只能调用nofityAll了。

    park和unpark模型真正解耦了线程之间的同步,线程之间不再需要一个Objec或者其他变量来存储状态,不再需要关心对方的状态。

    LockSupport API的使用

    LockSupport提供的阻塞和唤醒方法
    方法名 方法摘要
    static void park() 阻塞当前线程,如果调用了unpark(Thread thread)方法或者当前线程被中断,才能park()方法返回
    static void unpark() 唤醒处于阻塞状态的线程thread
    static void parkNanos(long nanos) 阻塞当前线程,最长不超过nanos纳米,返回条件在park()的基础上增加了超时返回
    static void parkUntil(long dealine) 在指定的时限前阻塞当前线程

    LockSupport 简单使用

    public static void main(String[] args) {
    
        Executor executor = Executors.newFixedThreadPool(2);
    
       Thread mainThread = Thread.currentThread() ;
    
        executor.execute(()->{
            try {
                Thread.sleep(3000L);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("start unpark main thread");
            LockSupport.unpark(mainThread);
            System.out.println("unpark main thread over");
        });
    
        System.out.println("before park");
        LockSupport.park();
        System.out.println("after park ");
    }
    

    运行结果:

    先释放许可,再获取许可

    @Test
    public void test1() {
        Thread thread = Thread.currentThread();
        LockSupport.unpark(thread);//释放许可
        LockSupport.park();// 获取许可
        System.out.println("b");
    }
    

    中断响应

    public static void main(String[] args) {
    
        Executor executor = Executors.newFixedThreadPool(2);
    
        Thread mainThread = Thread.currentThread() ;
    
        executor.execute(()->{
            try {
                Thread.sleep(3000L);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("start interrupt main thread");
            mainThread.interrupt();
            System.out.println("interrupt main thread over");
        });
    
        System.out.println("before park");
        LockSupport.park();
        LockSupport.park();
        System.out.println("after park ");
    }
    

    运行截图:

    原理和本文参考

    详见:Java的LockSupport.park()实现分析

  • 相关阅读:
    jenkins 配置git
    unittest 出报告 并配合 jenkins,发现有用例错误,但是构建没出现红点 的解决方法
    继承了2个类的使用方法 分别可以调用2个类里面的 方法 和 变量
    让HTMLrunner 报告的子列表都 默认展示出来的 方法(方便发送邮件时可以方便查看)
    Python:删除、增加字典的元素
    类里面变量相互调用的方法
    其他类想使用unittest的断言方法,就import unittest的框架,继承他,使用他里面的方法
    测试用例脚本 测试用例之间变量可以相互用的方法 实例
    测试用例脚本,调用其他模块方法的实例(数据分类 appium 和 selenium 看这里)
    类的继承 讲解
  • 原文地址:https://www.cnblogs.com/boothsun/p/7469099.html
Copyright © 2011-2022 走看看