java 方法区同步_Java实现任意条件的同步区临界条件

默认的synchronized变量或Lock锁,进入临界的条件可以认为是一个布尔值:

Lock lock= ...;

lock.lock();//一旦获取锁,其他线程就会在这里阻塞,即tryLock() == false

try{

//处理任务

}catch(Exception ex){

}finally{

lock.unlock();   //释放锁

}

这也是绝大多数线程同步代码需要处理的情况。

延伸思考:如果我们需要设计一种同步锁,临界条件不是布尔值而是其他条件,比如是一个数值,它允许这个数值在低于某个值前可以一直允许新的线程进入同步区。

这种需求在涉及某些硬件限制时特别常见,例如每个工作线程需要不定长的一段工作内存,而总工作内存是有限的区间。或者在移动设备上需要限制蓝牙设备的数目来避免触发某些bug。

一种常见的思考是在进入临界区之前判断某个数值:

if(mConditionCount > n) {

//do something

}

synchronized(this) {

......

}

这里需要解决两个问题:用什么方式判断以及如何利用这个数值?(总不能直接空转或者return返回)

如何避免增加额外的锁变量?(大部分稍有并发经验的同学都会想到尽可能只用一个锁解决问题)

下面介绍一种ConditionVariable的思路。ConditionVariable曾经出现在C#及Android的库函数中,但在很多服务端java架构中也有大量类似的应用。

这个类非常简单,并且可以解决以上的两个疑问,它在java中核心写法如下:

private volatile booleanmCondition;

publicvoidopen() {

synchronized(this) {

booleanold = mCondition;

mCondition= true;

if(!old) {

this.notifyAll();

}

}

}

public voidclose() {

synchronized(this) {

while(!mCondition) {

try{

this.wait();

} catch (InterruptedException e) {

}

}

mCondition= false;

}

}

public voidblock() {

synchronized(this) {

while(!mCondition) {

try{

this.wait();

}

catch (InterruptedException e) {

}

}

}

}

比一般的lock对象多了一个方法。它将同步临界条件拆解为三个方法:open(),block(),close()。block()尝试获取ConditionVariable的锁状态,若失败则阻塞。

close()令ConditionVariable上锁。一般block和close是连用的。

open()解除该ConditionVariable的锁状态。

它的典型使用代码是:

mConditionVariable.block();

mConditionVariable.close();

//临界区代码

mConditionVariable.open();

相比一般的Lock使用,容易看出这个类设计特别的地方在于:一个ConditionVariable实例实质是一个锁变量。

使用一个volatile的boolean变量mCondition来作为该锁的辅助修饰。

一个线程每次尝试获取锁并成功后,会跳过while循环进入后面的临界区代码。

若一个线程获取锁失败,此线程直接进入while循环把自己挂起。(此时这个锁的lock行为从阻塞变为直接挂起)

调用此锁的open()时所有线程走正常的notifyAll逻辑。

那么有些同学会有疑问:这个mCondition的辅助判断是否是线程安全的?通过检查代码发现所有对于mCondition的访问都要保持一个原则:这些访问应位于synchronized (this)的代码块内。此举可保障一切对于mCondition的操作都是队列化的。(如果你自己要从外部操作mCondition也是同理)

此时我们上面的延伸思考问题也就容易考虑了:

只需要把mCondition改为自己需要的变量类型即可。是否需要改为CAS?这个小问题可以自行思考。

//注意这种实现的锁是不可重入锁,有兴趣的同学可以自行思考如何改造为可重入锁

private static final int MAX_SYNC = 4;

private volatile intmCondition;

publicvoidopen() {

synchronized (this) {

intold = mCondition;

mCondition--;

if(old == 0) {

this.notifyAll();

}

}

}

public voidclose() {

synchronized(this) {

while(mCondition>= MAX_SYNC) {

try{

this.wait();

}

catch(InterruptedException e) {

}

}

mCondition++;

}

}

publicvoidblock() {

synchronized (this) {

while(mCondition>= MAX_SYNC) {

try{

this.wait();

}

catch(InterruptedException e) {

}

}

}

}

另外有个小问题,某些中文帖子里ConditionVariable.java的代码是有并发bug的。具体是什么bug对比代码一看便知,这里不再赘述。

对于本文代码有误或技术认知不深刻的地方欢迎指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值