Java多线程-LockSupport

x33g5p2x  于2022-02-16 转载在 Java  
字(2.2k)|赞(0)|评价(0)|浏览(479)

LockSupport介绍

学过wait/notify 应该都有觉得这个不太好用,因为不能唤醒自己想要的线程,只能随机唤醒一个线程或者全部线程都唤醒,处理不当甚至导致永久的阻塞情况,现在有了LockSupport之后线程的控制就由你自己掌控了,而且和wait/notify不冲突

共同点
LockSupport中的park方法和Object中的wait方法都可以使线程进入WAIT或者TIMED_WAIT状态
LockSupport中的unpark方法和Object中的notify可以使线程脱离WAIT、TIMED_WAIT状态
二者都可以通过调用线程的interrupt方法脱离等待状态
两者都是通过JVM层,也就是native代码实现的
不同点
Object中的wait方法在调用时当前线程必须要对该Object进行加锁,否则会抛出IllegalMonitorException。而LockSupport无需加锁,直接调用其静态方法park就可以使当前线程进入阻塞状态。
Object中wait和notify方法必须要按顺序调用,如果因为线程调度问题导致线程A先调用notify方法而线程B后调用wait方法,那么会使线程A永远处于WAIT状态。对于LockSupport而言则没有这种限制,如果有线程A首先调用了unpark方法并传入了线程B的引用,然后线程B再调用了park方法,那么线程B是不会进入等待状态的。
调用Object的wait方法后,可以调用该线程的interrupt方法脱离等待状态并捕获InterruptedException。而LockSupport并不能捕获InterruptedException。

上述方法不仅可以使当前线程进入等待状态,还可以设置一个对象赋给线程的parkBlocker对象,这个对象一般用于问题排查和系统的监控。

需要注意的是,在调用park方法并传入blocker对象后,只要该线程一直处于等待状态,都可以通过getBlocker方法获得该对象,但是当线程脱离上述状态后,就会将parkBlocker成员变量设为null。

LockSupport的park方法和unpark方法在JDK1.8中是基于sun.misc.Unsafe实现的,Unsafe直接提供了park和unpark方法,它们都是native方法,并在JVM层实现。

在上文我们对比Object和LockSupport时,我们提到了LockSupport的唤醒和等待可以乱序调用而不会时线程进入等待状态。这是因为Thread底层的Parker对象维护了一个许可,当首先调用unpark方法时,相当于给了这个线程一个许可,当再次调用park方法时,线程发现已经持有了这个许可后就不会进入等待状态了;如果线程发现没有许可,就会进入等待状态。

使用案例

//线程池方式
    @Test
    public void show2() {
        AtomicInteger num= new AtomicInteger();
        //生成者消费者
        ExecutorUtils.create(()->{
            LockSupportUtils.setAndclean("key2",()->{
                while (true) {
                    if (num.intValue() >= 10) {
                        LockSupportUtils.notifyLock("key1");
                        return;
                    }

                    if (num.intValue() == 0) {
                        //阻塞等待生产者生产
                        LockSupportUtils.waitLock();
                    } else {
                        System.out.println("消费者-消费"+num.intValue());
                        //唤醒生产者,然后自己阻塞
                        LockSupportUtils.notifyWaitLock("key1");
                    }
                }
            });
        });

        //生成生产者
        ExecutorUtils.create(()->{

            LockSupportUtils.setAndclean("key1",()->{
                while (true) {
                    if (num.intValue() >= 10) {
                        LockSupportUtils.notifyLock("key2");

                        return;
                    }
                    num.incrementAndGet();
                    System.out.println("生产者-生产"+num.intValue());
                    //唤醒指定消费者进行消费,然后阻塞自己
                    LockSupportUtils.notifyWaitLock("key2");
                }
            });
        });

        SleepTools.second(10);

    }

以上代码经提供参考,因为这是我二次封装后的

生产者-生产1
消费者-消费1
生产者-生产2
消费者-消费2
生产者-生产3
消费者-消费3
生产者-生产4
消费者-消费4
生产者-生产5
消费者-消费5
生产者-生产6
消费者-消费6
生产者-生产7
消费者-消费7
生产者-生产8
消费者-消费8
生产者-生产9
消费者-消费9
生产者-生产10

有了这个工具我们就可以灵活的控制线程之间的交互了
点赞 -收藏-关注-便于以后复习和收到最新内容有其他问题在评论区讨论-或者私信我-收到会在第一时间回复如有侵权,请私信联系我感谢,配合,希望我的努力对你有帮助^_^

相关文章