java共享锁实现原理及CountDownLatch解析

原创 2016年08月28日 23:44:00

前言

前面介绍了ReentrantLock,又叫排他锁,本篇主要通过CountDownLatch的学习来了解java并发包中是如何实现共享锁的。


CountDownLatch使用解说

CountDownLatch是java5中新增的一个并发工具类,其使用非常简单,下面通过伪代码简单看一下使用方式:

这里写图片描述

这是一个使用CountDownLatch非常简单的例子,创建的时候,需要指定一个初始状态值,本例为2,主线程调用 latch.await时,除非latch状态值为0,否则会一直阻塞休眠。当所有任务执行完后,主线程唤醒,最终执行打印动作。

以上只是一个最简单的例子,接着咱们再来看一个,这回,咱们想要在任务执行完后做更多的事情,如下图所示:

这里写图片描述

这一次,在线程3和线程4中,分别调用了latch.await(),当latch状态值为0时,这两个线程将会继续执行任务,但是顺序性是无法保证的。

CountDownLatch的方便之处在于,你可以在一个线程中使用,也可以在多个线程上使用,一切只依据状态值,这样便不会受限于任何的场景。


java共享锁模型

在java5提供的并发包下,有一个AbstractQueuedSynchronizer抽象类,也叫AQS,此类根据大部分并发共性作了一些抽象,便于开发者实现如排他锁,共享锁,条件等待等更高级的业务功能。它通过使用CAS和队列模型,出色的完成了抽象任务,在此向Doug Lea致敬。

AQS比较抽象,并且是优化精简的代码,如果一头扎进去,可能会比较容易迷失。本篇只解说CountDownLatch中使用到的共享锁模型。

我们以CountDownLatch第二个例子作为案例来分析一下,一开始,我们创建了一个CountDownLatch实例,

这里写图片描述

此时,AQS中,状态值state=2,对于 CountDownLatch 来说,state=2表示所有调用await方法的线程都应该阻塞,等到同一个latch被调用两次countDown后才能唤醒沉睡的线程。接着线程3和线程4执行了 await方法,这会的状态图如下:

这里写图片描述

注意,上面的通知状态是节点的属性,表示该节点出队后,必须唤醒其后续的节点线程。当线程1和线程2分别执行完latch.countDown方法后,会把state值置为0,此时,通过CAS成功置为0的那个线程将会同时承担起唤醒队列中第一个节点线程的任务,从上图可以看出,第一个节点即为线程3,当线程3恢复执行之后,其发现状态值为通知状态,所以会唤醒后续节点,即线程4节点,然后线程3继续做自己的事情,到这里,线程3和线程4都已经被唤醒,CountDownLatch功成身退。

上面的流程,如果落实到代码,把 state置为0的那个线程,会判断head指向节点的状态,如果为通知状态,则唤醒后续节点,即线程3节点,然后head指向线程3节点,head指向的旧节点会被删除掉。当线程3恢复执行后,发现自身为通知状态,又会把head指向线程4节点,然后删除自身节点,并唤醒
线程4。

这里可能读者会有个疑问,线程节点的状态是什么时候设置上去的。其实,一个线程在阻塞之前,就会把它前面的节点设置为通知状态,这样便可以实现链式唤醒机制了。


结束语

本篇从CountDownLatch入手讲解AQS中的共享锁模式,主要是由CountDownLatch的实现相对简单,但却实现了共享锁模型,如果在理解了模型的基础上,从CountDownLatch入手来看AQS关于共享锁的代码还比较好看懂,在看的时候,建议以看懂大致内容为主,学习其设计的思路,不要陷入所有条件处理细节中,多线程环境中,对与错有时候不是那么容易看出来的。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

CountDownLatch理解一:与join的区别

首先,我们来看一个应用场景1: 假设一条流水线上有三个工作者:worker0,worker1,worker2。有一个任务的完成需要他们三者协作完成,worker2可以开始这个任务的前提是worker0...

CountDownLatch 和 CyclicBarrier 的运用及实现原理

CountDownLath和CyclicBarrier用法简介以及原理浅析

CountDownLatch的介绍和使用

1、类介绍 java.util.concurrent 类 CountDownLatch java.lang.Object java.util.concurrent.CountDownL...

java并发-独占锁与共享锁

1 锁的独占与共享       java并发包提供的加锁模式分为独占锁和共享锁,独占锁模式下,每次只能有一个线程能持有锁,ReentrantLock就是以独占方式实现的互斥锁。共享锁,则允许多个线程同...

共享锁和排它锁(ReentrantReadWriteLock)

1、什么是共享锁和排它锁      共享锁就是允许多个线程同时获取一个锁,一个锁可以同时被多个线程拥有。      排它锁,也称作独占锁,一个锁在某一时刻只能被一个线程占有,其它线程必须等待锁被释...

Java之CountDownLatch使用

CountDownLatch 1、类介绍 一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。用给定的计数 初始化 CountDownLatch。由于...

Java并发学习之十七——线程同步工具之CountDownLatch

本文是学习网络上的文章时的总结,感谢大家无私的分享。 CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个...

CountDownLatch用法

CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。...

Java 并发专题 :闭锁 CountDownLatch 之一家人一起吃个饭

最近一直整并发这块东西,顺便写点Java并发的例子,给大家做个分享,也强化下自己记忆。 每天起早贪黑的上班,父母每天也要上班,话说今天定了个饭店,一家人一起吃个饭,通知大家下班去饭店集合。假设:3个人...

java并发编程之--CountDownLatch

java并发笔记之–CountDownLatch知乎 decodelife,转载请注明出处本文为java并发笔记系列之— CountDownLatch概念单词Latch,中文翻译是门闩,也就是有“门锁...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:java共享锁实现原理及CountDownLatch解析
举报原因:
原因补充:

(最多只允许输入30个字)