Java并发实现线程阻塞原语LockSupport

摘要:
LockSupport和CAS是Java并发包中很多并发工具控制机制的基础,它们底层其实都是依赖Unsafe实现。LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。LockSupport和每个使用它的线程都与一个许可关联。自己动手写把”锁”---LockSupport深入浅出浅谈Java并发编程系列(八)——LockSupport原理剖析

LockSupport 和 CAS 是Java并发包中很多并发工具控制机制的基础,它们底层其实都是依赖Unsafe实现。LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。

1、LockSupport原理

LockSupport是只有静态方法且构造函数私有,对外给线程提供各种版本的park()和unpark()方法实现阻塞线程和解除线程阻塞。

LockSupport和每个使用它的线程都与一个许可(permit)关联。permit类似信号量,相当于1,0的开关,默认是0,调用一次unpark被置为1,调用一次park会消费permit, 也就是将1变成0,同时park立即返回。再次调用park会变成block(因为permit为0了,会阻塞在这里,直到permit变为1), 这时调用unpark会把permit置为1。每个线程都有一个相关的permit, permit最多只有一个,重复调用unpark也不会积累。

park()和unpark()不会有 “Thread.suspend和Thread.resume所可能引发的死锁” 问题,由于许可的存在,调用 park 的线程和另一个试图将其 unpark 的线程之间的竞争将保持活性。

如果调用线程被中断,则park方法会返回。同时park也拥有可以设置超时时间的版本。

需要特别注意的一点:park 方法还可以在其他任何时间“毫无理由”地返回,因此通常必须在重新检查返回条件的循环里调用此方法。从这个意义上说,park 是“忙碌等待”的一种优化,它不会浪费这么多的时间进行自旋,但是必须将它与 unpark 配对使用才更高效。

2、LockSupport与Object的wait/notify对比

在Java6引入LockSupport以前,线程挂起和唤醒要通过Object的wait和notify/notifyAllfangAll实现,但后者必须要在同步块里调用,且notify必须要在wait之后调用才行否则会导致线程阻塞。

public classTestObjWait {
    public static void main(String[] args)throwsException {
        final Object obj = newObject();
        Thread A = new Thread(newRunnable() {
            @Override
            public voidrun() {
                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();
        }
    }
}
public classTestObjWait {
    public static void main(String[] args)throwsException {
        Thread A = new Thread(newRunnable() {
            @Override
            public voidrun() {
                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调用,所以不需要担心线程间的执行的先后顺序。

3、LockSupport应用

LockSupport在Java工具类中用的很广泛,如并发锁基础AQS、线程池ThreadPoolExecutor等。

自己动手写把”锁”---LockSupport深入浅出

浅谈Java并发编程系列(八)—— LockSupport原理剖析

免责声明:文章转载自《Java并发实现线程阻塞原语LockSupport》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇C# 与 VB.NET 对比慢查询日志(mysql)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

【C/C++多线程编程之五】pthread线程深入理解

多线程编程之pthread线程深入理解       Pthread是 POSIX threads 的简称,是POSIX的线程标准。           前几篇博客已经能给你初步的多线程概念。在进一步学习线程同步等多线程核心知识之前,须要对多线程深入的理解。非常多人忽略或者回避这部分内容,直接的问题是学习者无法把握多线程编程的内在原理,理解的层次太浅。...

Go(四) 并发编程

一、基本概念 并行和并发 并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行。 需要CPU多核 并发(concurrency):指在同一时刻只能有一条指令执行,当多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行,只是时间分成若干段,通过CPU时间片轮转使得多个进程快速交替执行。 进程并发...

[置顶]C#中Socket服务端代码分享

最近在对项目中Socket通讯中的服务端代码进行优化,保证能接受尽可能多的客户端的连接,并且不会丢掉连接,不会掉数据包。经过一段时间的反复测试和修改,终于达到了这一要求。服务端代码采用了异步通讯的方式,并使用ManualResetEvent来对线程进行控制。在程序中,ManualResetEvent 的使用很关键。 ManualResetEvent 允许线...

【转】JMeter学习(三十二)属性和变量

一、Jmeter中的属性: 1、JMeter属性统一定义在jmeter.properties文件中,我们可以在该文件中添加自定义的属性 2、JMeter属性在测试脚本的任何地方都是可见的(全局),通常被用来定义一些JMeter使用的默认值,可以用于在线程间传递信息。 3、JMeter属性可以在测试计划中通过函数 _P 进行引用,但是不能作为特定线程的变量值...

排查线上内存泄漏,RingBufferLogEvent类内存占用过高,skyWalking内存占用过高

项目运行了一段时间 运维那边反馈项目内存过高,首先我们把线上的jvm内存文件导出来,来看看哪些对象有问题 , 我这边演示就在windows中的cmd演示了  因为jdk提供的命令都一样 1查看java进程  命令: jps-l 可以看到我们的java进程id是 149992 2导出内存文件到本地,如果是在服务器中需要把文件 下载到本地做分析  命令:jm...

web 服务的基础介绍

1>web 服务的访问流程          1.电脑浏览器网页上输入请求的地址          2.服务器接收到请求          3.服务器响应请求          4.将响应的数据返回给客户端 2>  apache 的三种工作模型(面试)               select ;work;event           2...