• LockSupport的深入浅出



    public static void main(String[] args)throws Exception { final Object obj = new Object(); Thread A = new Thread(new Runnable() { @Override public void run() { int sum = 0; for(int i=0;i<10;i++){ sum+=i; } try { synchronized (obj){ obj.wait(); } }catch (Exception e){ e.printStackTrace(); } System.out.println(sum); } }); A.start(); //睡眠一秒钟,保证线程A已经计算完成,阻塞在wait方法 //Thread.sleep(1000); synchronized (obj){ obj.notify(); } }

    LockSupport是JDK中比较底层的类,用来创建锁和其他同步工具类的基本线程阻塞原语。java锁和同步器框架的核心AQS:AbstractQueuedSynchronizer,就是通过调用LockSupport.park()和LockSupport.unpark()实现线程的阻塞和唤醒的。LockSupport很类似于二元信号量(只有1个许可证可供使用),如果这个许可还没有被占用,当前线程获取许可并继续执行如果许可已经被占用,当前线程阻塞,等待获取许可
    permit相当于1,0的开关,默认是0,调用一次unpark就加1变成1,调用一次park会消费permit, 也就是将1变成0,同时park立即返回。再次调用park会变成block(因为permit为0了,会阻塞在这里,直到permit变为1), 这时调用unpark会把permit置为1。每个线程都有一个相关的permit, permit最多只有一个,重复调用unpark也不会积累。

    LockSupport函数列表

    // 返回提供给最近一次尚未解除阻塞的 park 方法调用的 blocker 对象,如果该调用不受阻塞,则返回 null。
    static Object getBlocker(Thread t)
    // 为了线程调度,禁用当前线程,除非许可可用
    static void park()
    // 为了线程调度,在许可可用之前禁用当前线程。
    static void park(Object blocker)
    // 为了线程调度禁用当前线程,最多等待指定的等待时间,除非许可可用。
    static void parkNanos(long nanos)
    // 为了线程调度,在许可可用前禁用当前线程,并最多等待指定的等待时间。
    static void parkNanos(Object blocker, long nanos)
    // 为了线程调度,在指定的时限前禁用当前线程,除非许可可用。
    static void parkUntil(long deadline)
    // 为了线程调度,在指定的时限前禁用当前线程,除非许可可用。
    static void parkUntil(Object blocker, long deadline)
    // 如果给定线程的许可尚不可用,则使其可用。
    static void unpark(Thread thread)

    说明:LockSupport是通过调用Unsafe函数中的接口实现阻塞和解除阻塞的

    下面是unpark的英文

    Makes available the permit for the given thread, if it was not already available. If the thread was blocked on park then it will unblock. Otherwise, its next call to park is guaranteed not to block. This operation is not guaranteed to have any effect at all if the given thread has not been started.

    使给定线程的许可证可用(如果它还没有可用)。如果线程在park上被阻塞,那么它将解阻塞。否则,它下次调用park时,保证不会阻塞。如果没有启动给定的线程,则不能保证此操作具有任何效果。

    下面是park的英文

    Disables the current thread for thread scheduling purposes unless the permit is available.
    If the permit is available then it is consumed and the call returns immediately; otherwise the current thread becomes disabled for thread scheduling purposes and lies dormant until one of three things happens:
    Some other thread invokes unpark with the current thread as the target; or
    Some other thread interrupts the current thread; or
    The call spuriously (that is, for no reason) returns.
    This method does not report which of these caused the method to return. Callers should re-check the conditions which caused the thread to park in the first place. Callers may also determine, for example, the interrupt status of the thread upon return.

    除非有许可证,否则为线程调度目的禁用当前线程。【也就是说默认任何线程调用都会被阻塞,因为没有对应许可证,只有调用完unpark分配给线程许可证,才可以执行任务
    如果许可证是可用的,那么它将被使用,调用立即返回;否则,当前线程将出于线程调度的目的被禁用,并处于休眠状态,直到以下三种情况之一发生:
    其他一些线程以当前线程为目标调用unpark;或
    其他一些线程中断当前线程;或
    虚假的调用(也就是说,没有理由)返回。
    此方法不报告是哪些原因导致该方法返回。调用者应该重新检查导致线程首先停车的条件。例如,调用者还可以在返回时确定线程的中断状态。

    先看上面那段代码  用notify wait来阻塞和唤醒线程 有几个弊端  首先加入notify wait的代码都需要内置锁 还有就是不能保证顺序   像上面那段代码有可能主线程先调用notify然后wait就一直阻塞了

    public class TestObjWait {
    
        public static void main(String[] args)throws Exception {
            final Object obj = new Object();
            Thread A = new Thread(new Runnable() {
                @Override
                public void run() {
                    int sum = 0;
                    for(int i=0;i<10;i++){
                        sum+=i;
                    }
                    LockSupport.park();
                    System.out.println(sum);
                }
            });
            A.start();
            //睡眠一秒钟,保证线程A已经计算完成,阻塞在wait方法
            //Thread.sleep(1000);
            LockSupport.unpark(A);
        }
    }像上面这段代码 无论执行多少次 结果都能准确输出。

    总结一下,LockSupport比Object的wait/notify有两大优势

    ①LockSupport不需要在同步代码块里 。所以线程间也不需要维护一个共享的同步对象了,实现了线程间的解耦。

    unpark函数可以先于park调用,所以不需要担心线程间的执行的先后顺序

  • 相关阅读:
    支付宝支付私钥和公钥创建
    (五)Maven中的聚合和继承
    Windows 下Nexus搭建Maven私服
    (四)Maven中的仓库
    zookeeper安装和使用 windows环境
    (一)Redis之简介和windows下安装radis
    (错误) Eclipse使用Maven创建Web时错误
    (三)引用中央仓库中不存在的jar包
    (二)依赖传递
    (一)Maven基础及第一个Maven工程
  • 原文地址:https://www.cnblogs.com/zhangfengshi/p/10449043.html
Copyright © 2020-2023  润新知