java线程(九)之LockSupport

版权声明:本文是作者在学习与工作中的总结与笔记,如有内容是您的原创,请评论留下链接地址,我会在文章开头声明。 https://blog.csdn.net/usagoole/article/details/89789276

文章目录

LockSupport

  1. LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。
  2. LockSupport中的park()unpark() 的作用分别是阻塞线程和解除阻塞线程,而且park()unpark()不会遇到Thread.suspendThread.resume所可能引发的死锁”问题。
  3. 因为park()unpark()有许可的存在;调用park()的线程和另一个试图将其 unpark()的线程之间的竞争将保持活性。
  4. unpark函数为线程提供"许可(permit)",线程调用park()则等待"许可"。这个有点像信号量,但是这个"许可"是不能叠加的,“许可"是一次性的。比如线程B连续调用了三次unpark(),当线程A调用park()就使用掉这个"许可”,如果线程A再次调用park(),则进入等待状态。
  5. 注意,unpark()可以先于park()调用。比如线程B调用unpark(),给线程A发了一个"许可",那么当线程A调用park()时,它发现已经有"许可"了,那么它会马上再继续运行。park/unpark模型真正解耦了线程之间的同步,线程之间不再需要一个Object或者其它变量来存储状态,不再需要关心对方的状态。LockSupport很类似于二元信号量(只有1个许可证可供使用)

方法

  1. 方法

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

案例

  1. 案例一:运行该代码,可以发现主线程一直处于阻塞状态。因为许可默认是被占用的,调用park()时获取不到许可,所以进入阻塞状态。

        @Test
        public void testPack1() {
            LockSupport.park();
            //不会打印
            System.out.println("block.");
        }
    
    
  2. 案例二:先释放许可,再获取许可,主线程能够正常终止。LockSupport许可的获取和释放,一般来说是对应的,如果多次unpark,只有一次park也不会出现什么问题,结果是许可处于可用状态。

        @Test
        public void testUnpark() {
            Thread thread = Thread.currentThread();
            // 释放许可
            LockSupport.unpark(thread);
            // 获取许可
            LockSupport.park();
            System.out.println("b");
        }
        
         /**
         * 输出 a b c
         */
        @Test
        public void testPark3() {
            Thread thread = Thread.currentThread();
            LockSupport.unpark(thread);
            System.out.println("a");
            LockSupport.park();
            System.out.println("b");
            LockSupport.unpark(thread);
            LockSupport.park();
            System.out.println("c");
        }
    
  3. 案例三:LockSupport是不可重入的,如果一个线程连续2次调用LockSupport.park(),那么该线程一定会一直阻塞下去。

            /**
             * 输出 a b
             * LockSupport是不可重入的,如果一个线程连续2次调用LockSupport.park(),
             * 那么该线程一定会一直阻塞下去。
             */
            @Test
            public void testPark2() {
                Thread thread = Thread.currentThread();
                LockSupport.unpark(thread);
                System.out.println("a");
                LockSupport.park();
                System.out.println("b");
                LockSupport.park();
                System.out.println("c");
            }
            
    
    
  4. 案例四:线程如果因为调用park()而阻塞的话,能够响应中断请求(中断状态被设置成true),但是不会抛出InterruptedException

        /**
         * 输出:
         *      after 1 second.count=26787704
         *      main over
         *      thread over.true
         *   最终线程会打印出thread over.true。这说明线程如果因为调用park而阻塞的话,
         *   能够响应中断请求(中断状态被设置成true),但是不会抛出InterruptedException。
         */
        @Test
        public void testInterrupt() {
            Thread t = new Thread(new Runnable() {
                private int count = 0;
    
                @Override
                public void run() {
                    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();
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            // 中断线程
            t.interrupt();
            System.out.println("main over");
        }
    

猜你喜欢

转载自blog.csdn.net/usagoole/article/details/89789276
今日推荐