• 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()实现分析

  • 相关阅读:
    log4net preserveLogFileNameExtension 和 watch
    BootStrap自带的图标
    git fetch批处理,遍历一个文件夹下的所有子目录,执行git fetch --all
    Recommended Settings for Tracing and Message Logging
    蜗牛—JSONJ学习ava转变
    Do you master on array in C ?
    全面推行使用智能指针的权利
    2014/08/23——OJ出现waiting...
    在Windows通过使用MinGW静态编译Assimp
    Ubuntu12.04password正确 入口的桌面(测试的恢复正常)
  • 原文地址:https://www.cnblogs.com/boothsun/p/7469099.html
Copyright © 2020-2023  润新知