• Java多线程 LockSupport


    在AQS里面进行阻塞线程,解除阻塞线程就用的LockSupport。

    JDK1.8源码:

    package java.util.concurrent.locks;
    import sun.misc.Unsafe;
    
    public class LockSupport {
        private LockSupport() {} // Cannot be instantiated.
    
        private static void setBlocker(Thread t, Object arg) {
            // Even though volatile, hotspot doesn't need a write barrier here.
            UNSAFE.putObject(t, parkBlockerOffset, arg);
        }
    
        public static void unpark(Thread thread) {
            if (thread != null)
                UNSAFE.unpark(thread);
        }
    
        public static void park(Object blocker) {
            Thread t = Thread.currentThread();
            setBlocker(t, blocker);
            UNSAFE.park(false, 0L);
            setBlocker(t, null);
        }
    
        public static void parkNanos(Object blocker, long nanos) {
            if (nanos > 0) {
                Thread t = Thread.currentThread();
                setBlocker(t, blocker);
                UNSAFE.park(false, nanos);
                setBlocker(t, null);
            }
        }
    
        public static void parkUntil(Object blocker, long deadline) {
            Thread t = Thread.currentThread();
            setBlocker(t, blocker);
            UNSAFE.park(true, deadline);
            setBlocker(t, null);
        }
    
        public static Object getBlocker(Thread t) {
            if (t == null)
                throw new NullPointerException();
            return UNSAFE.getObjectVolatile(t, parkBlockerOffset);
        }
    
        public static void park() {
            UNSAFE.park(false, 0L);
        }
    
        public static void parkNanos(long nanos) {
            if (nanos > 0)
                UNSAFE.park(false, nanos);
        }
    
        public static void parkUntil(long deadline) {
            UNSAFE.park(true, deadline);
        }
        
        static final int nextSecondarySeed() {
            int r;
            Thread t = Thread.currentThread();
            if ((r = UNSAFE.getInt(t, SECONDARY)) != 0) {
                r ^= r << 13;   // xorshift
                r ^= r >>> 17;
                r ^= r << 5;
            }
            else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)
                r = 1; // avoid zero
            UNSAFE.putInt(t, SECONDARY, r);
            return r;
        }
    
        // Hotspot implementation via intrinsics API
        private static final sun.misc.Unsafe UNSAFE;
        private static final long parkBlockerOffset;
        private static final long SEED;
        private static final long PROBE;
        private static final long SECONDARY;
        static {
            try {
                UNSAFE = sun.misc.Unsafe.getUnsafe();
                Class<?> tk = Thread.class;
                parkBlockerOffset = UNSAFE.objectFieldOffset
                    (tk.getDeclaredField("parkBlocker"));
                SEED = UNSAFE.objectFieldOffset
                    (tk.getDeclaredField("threadLocalRandomSeed"));
                PROBE = UNSAFE.objectFieldOffset
                    (tk.getDeclaredField("threadLocalRandomProbe"));
                SECONDARY = UNSAFE.objectFieldOffset
                    (tk.getDeclaredField("threadLocalRandomSecondarySeed"));
            } catch (Exception ex) { throw new Error(ex); }
        }
    }
    View Code

    LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。 
    LockSupport中的park() 和 unpark() 的作用分别是阻塞线程和解除阻塞线程,而且park()和unpark()不会遇到“Thread.suspend 和 Thread.resume所可能引发的死锁”问题。
    因为park() 和 unpark()有许可的存在;调用 park() 的线程和另一个试图将其 unpark() 的线程之间的竞争将保持活性。

    方法列表:

    // 返回提供给最近一次尚未解除阻塞的 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)

    demo:

    import java.util.concurrent.locks.LockSupport;
    
    public class Main {
        public static void main(String[] args) throws InterruptedException {
            Thread thread = Thread.currentThread();
            LockSupport.unpark(thread);
            LockSupport.park();
            System.out.println("b");
        }
    }

    结果为b,先释放许可,再获取许可,主线程能够正常终止。LockSupport许可的获取和释放,一般来说是对应的,如果多次unpark,只有一次park也不会出现什么问题,结果是许可处于可用状态。

    import java.util.concurrent.locks.LockSupport;
    
    public class Main {
        public static void main(String[] args) throws InterruptedException {
            Thread thread = Thread.currentThread();
            LockSupport.unpark(thread);
            System.out.println("a");
            LockSupport.park();
            System.out.println("b");
            LockSupport.park();
            System.out.println("c");
        }
    }
    a
    b
    View Code

    LockSupport是不重入的,如果一个线程连续2次调用LockSupport.park(),那么该线程一定会一直阻塞下去。

    import java.util.concurrent.locks.LockSupport;
    
    public class Main {
        public static void main(String[] args) throws InterruptedException {
            Thread t = new Thread(new Runnable()
            {
                private int count = 0;
                @Override
                public void run()
                {
                    System.out.println("start");
                    long start = System.currentTimeMillis();
                    long end = 0;
                    while ((end - start) <= 1000)
                    {
                        count++;
                        end = System.currentTimeMillis();
                    }
                    System.out.println("after 1 second.count=" + count);
                    //等待或许许可
                    LockSupport.park();
                    System.out.println("thread over." + Thread.currentThread().isInterrupted());
    
                }
            });
            t.start();
            Thread.sleep(2000);
            // 中断线程
            t.interrupt();
            System.out.println("main over");
        }
    }
    start
    after 1 second.count=73186612
    main over
    thread over.true
    View Code

    最终线程会打印出thread over.true。这说明线程如果因为调用park而阻塞的话,能够响应中断请求(中断状态被设置成true),但是不会抛出InterruptedException

    park和wait的区别:wait让线程阻塞前,必须通过synchronized获取同步锁。

    总结起来LockSupport有以下不同和特点:
    其实现机制和wait/notify有所不同,面向的是线程。
    不需要依赖监视器
    与wait/notify没有交集
    使用起来更加灵活方便

    http://www.cnblogs.com/skywang12345/p/3505784.html

    https://my.oschina.net/readjava/blog/282882

    http://blog.csdn.net/aitangyong/article/details/38373137?utm_source=tuicool&utm_medium=referral

    https://www.zhihu.com/question/26471972

    http://blog.csdn.net/opensure/article/details/53349698

  • 相关阅读:
    encodeURIComponent编码时为什么要编码两次
    JS校验身份证号的合法性
    react-router与react-router-dom使用时的区别
    数组去重
    window的cmd命令行下新增/删除文件夹及文件
    数组排序【冒泡排序、快速排序、选择排序】
    个人搭建后台管理模板 Bootstrap4 ,ASP.NET Core,EF Core,JWT
    个人搭建后台管理模板 Bootstrap4 ,ASP.NET Core,EF Core,JWT
    react-starter-projects
    基于H.ui.Admin UI模板的网站管理后台
  • 原文地址:https://www.cnblogs.com/hongdada/p/6155545.html
Copyright © 2020-2023  润新知