• 【LockSupport】概述、阻塞⽅法park、唤醒⽅法unpark(thread)、 解决的痛点、带来的⾯试题_JUC19


    1、什么是LockSupport?

    • ①. 通过park()和unpark(thread)⽅法来实现阻塞唤醒线程的操作。

    • ②. LockSupport是⼀个线程阻塞⼯具类,所有的⽅法都是静态⽅法,可以让线程在任意位置阻塞,阻塞之后也有对应的唤醒⽅法。归根结底,LockSupport调⽤的Unsafe中的native代码

    • ③. 官⽹解释:

      • LockSupport是⽤来创建锁和其他同步类基本线程阻塞原语

      • LockSupport类使⽤了⼀种名为Permit(许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有⼀个许可

        (permit)permit只有两个值1和零,默认是零。

      • 可以把许可看成是⼀种(0,1)信号量(Semaphore),但与Semaphore不同的是,许可的累加上限是1


    2、阻塞⽅法

    • ①. permit默认是0,所以⼀开始调⽤park()⽅法,当前线程就会阻塞,直到别的线程将当前线程的permit设置为1时park⽅法会被唤醒,然后就会消耗掉1个permit再次变为为0并返回。
    • ②. static void park( ):底层是unsafe类native⽅法

    在这里插入图片描述


    3、唤醒⽅法(注意这个permit最多只能为1)

    • ①. 调⽤unpark(thread)⽅法后,就会将thread线程的许可permit设置成1(注意多次调⽤unpark⽅法,不会累加,permit值还是1)会⾃动唤醒thread线程,即之前阻塞中的LockSupport.park()⽅法会⽴即返回。
    • ②. static void unpark( )。

    在这里插入图片描述


    4、LockSupport它的解决的痛点?(他主要的作用是什么?)

    • ①. LockSupport不⽤持有锁块不⽤加锁程序性能好
    • ②. 先后顺序,不容易导致卡死(因为调用unpark获得⼀个凭证,之后再调⽤park⽅法,就可以名正⾔顺的凭证消费,故不会阻塞)
    /*
    (1).阻塞
    	permit默认是O,所以一开始调用park()方法,当前线程就会阻塞,直到别的线程将当前线程的permit设置为1时,park方法会被唤醒,然后会将permit再次设置为O并返回。
    	static void park()
    	static void park(Object blocker)
     
    (2).唤醒
    	调用unpark(thread)方法后,就会将thread线程的许可permit设置成1(注意多次调用unpark方法,不会累加,permit值还是1)会自动唤醒thread线程,即之前阻塞中的LockSupport.park()方法会立即返回。
    	static void unpark(Thread thread)
    */
    public class LockSupportDemo {
        public static void main(String[] args) {
    		
            //线程A
            Thread t1=new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"\t"+"coming....");
                LockSupport.park();
                /*
                如果这里有两个LockSupport.park(),因为permit的值为1,上一行已经使用了permit
                所以下一行被注释的打开会导致程序处于一直等待的状态
                * */
                //LockSupport.park();
                System.out.println(Thread.currentThread().getName()+"\t"+"被B唤醒了");
                }"A");
            t1.start();
    
            
            //下面代码注释是为了A线程先执行
            try { TimeUnit.SECONDS.sleep(3);  } catch (InterruptedException e) {e.printStackTrace();}
    
            //线程B
            Thread t2=new Thread(()->{
                System.out.println(Thread.currentThread().getName()+"\t"+"唤醒A线程");
                
                //有两个LockSupport.unpark(t1),由于permit的值最大为1,所以只能给park一个通行证。
                LockSupport.unpark(t1);
                //LockSupport.unpark(t1);
            }"B");
            
            t2.start();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    5、LockSupport ⾯试题⽬

    • ①. 为什么可以先唤醒线程后阻塞线程?
      • 因为调用unpark可以先获得了⼀个凭证,之后再调⽤park⽅法,就可以名正⾔顺的凭证消费,故不会阻塞。
    • ②. 为什么唤醒两次后阻塞两次,但最终结果还会阻塞线程?
      • 因为凭证的数量最多为1,连续调⽤两次unpark和调⽤⼀次unpark效果⼀样只会增加⼀个凭证;⽽调⽤两次park却需要消费两个凭证证不够,不能放⾏
  • 相关阅读:
    Python实现番茄小说内容下载
    常用的git命令(实用)
    Vue3中使用Element-Plus分页组件
    一个超好看的音乐网站设计与实现(HTML+CSS)
    LRU机制实现
    Stream流的使用
    【Android抓包】Ubuntu mitmProxy配置
    神经网络入门(一)
    uboot移植之环境变量bootargs
    Vue-生命周期函数
  • 原文地址:https://blog.csdn.net/weixin_38963649/article/details/126144639