从JDK源码角度看并发竞争的超时

JDK中的并发框架提供的另一个优秀机制是锁获取超时的支持,当大量线程对某一锁竞争时可能致使某些线程在很长一段时间都获取不了锁,在某些场景下可能但愿若是线程在一段时间内不能成功获取锁就取消对该锁的等待以提升性能,这时就须要用到超时机制。在JDK1.5以前并无对此支持,当时的并发控制职能经过JVM内置的synchronized关键词实现锁,但对一些特殊要求却力不从心,例如超时取消控制。JDK1.5开始引入并发工具完美解决了此问题,JDK对并发线程开始提供超时的支持。java

为了更精确地保证时间间隔统计的准确性,实现时使用了System.nanoTime()更为精确的方法,它能精确到纳秒级别。超时机制的思想就是在不断进行锁竞争的同时记录竞争的时间,一旦时间段超过指定的时间则中止轮询直接返回,返回前对等待队列中对应节点进行取消操做。往下看实现的逻辑:node

if(尝试获取锁失败) {
    long lastTime = System.nanoTime();
    建立node
    使用CAS方式把node插入到队列尾部
    while(true){
        if(尝试获取锁成功 而且 node的前驱节点为头节点){
            把当前节点设置为头节点
            跳出循环
        }else{
            if (nanosTimeout <= 0){
                取消等待队列中此节点
                跳出循环
            }
            使用CAS方式修改node前驱节点的waitStatus标识为signal if(修改为功) if(nanosTimeout > spinForTimeoutThreshold) 阻塞当前线程nanosTimeout纳秒 long now = System.nanoTime();
            nanosTimeout -= now - lastTime;
            lastTime = now;
        }
    }
}复制代码

上面正在锁的获取逻辑中添加超时处理,核心逻辑是不断循环减去处理的时间消耗,一旦小于0就取消节点并跳出循环,其中有两点必需要注意,一个是真正的阻塞时间应该是扣除了竞争入队的时间后剩余的时间,保证阻塞事件的准确性,咱们能够看到每次循环都会减去相应的处理时间;另一个是关于spinForTimeoutThreshold变量阀值,它是决定使用自旋方式消耗时间仍是使用系统阻塞方式消耗时间的分割线,JDK并发工具包做者经过测试将默认值设置为1000ns,即若是在成功插入等待队列后剩余时间大于1000ns则调用系统底层阻塞,不然不调用系统底层,取而代之的是仅仅让之在Java应用层不断循环消耗时间,属于优化的措施。并发

至此,JDK实如今获取锁的过程当中提供了超时机制,超时的支持让Java在并发方面提供了更完善的机制,更多的并发策略知足开发者更多需求。框架

欢迎关注
工具

相关文章
相关标签/搜索