可重入锁ReentrantLock与Condition

一、可重入锁ReentrantLock

可重入锁可以完全替代synchronized,与synchronized相比,ReentrantLock是显式操作,需要手动指定何时加锁,何时释放锁。

之所以称之为可重入锁,是因为一个线程可以连续两次获得同一把锁,例如:

lock.lock();
lock.lock();
try{
	i++;
}
finally{
	lock.unlock();
	lock.unlock();
}

如果不允许这种操作的话,那么将会在第二次请求锁的时候和自己产生死锁。注意,一个线程多次获得锁,释放锁的时候,必须释放相同数目的锁。

•中断响应

对于synchronized来说,如果一个线程在等待锁,那么只有两种结果,一个是获得锁后继续执行,一个是保持等待。对于可重入锁来说还有额外的一种情况,那就是线程可以被中断。这有助于解决死锁问题。加锁的时候使用lock.lockInterruptibly(),这样线程就可以响应中断。

•锁申请等待限时

ReentrantLock中有一个tryLock()方法,在申请锁的时候会等待一段时间,超时后如果还得不到锁,则线程会自动放弃,这也可以有效解决死锁问题。tryLock()方法有两个参数,第一个表示等待时长,第二个表示计时单位。比如,tryLock(5, TimeUnit.SECONDS)表示等待5秒,如果5秒之内获得锁,则返回true;如果超过5秒仍未获得锁,则返回false。tryLock()也可以不带参数,那么它就会立即返回true或者false。

•公平锁

大多数情况下,锁的申请都是非公平的。也就是说现申请锁的线程不一定先得到锁。系统只是会从锁的等待队列中随机选择一个线程。而公平锁就是按照时间先后顺序,先申请者先得,后申请者后得。synchronized就是非公平锁,使用ReentrantLock可以设置锁的公平性。其有一个构造函数:public ReentrantLock(boolean fair)。当fair为true的时候就是公平锁,默认是非公平锁。

实现公平锁必然要求系统维护一个有序队列,实现成本较高,性能较低。一般情况下,不需要使用公平锁。

ReentrantLock的方法总结如下:

lock():获得锁,如果锁已经被占用则等待。

lockInterruptibly():获得锁,但是优先响应中断。

tryLock():尝试获得锁,如果成功,返回true,失败返回false。该方法不等待。

tryLock(long time, TimeUnit.unit):在给定的时间内尝试获得锁。

unlock():释放锁。

二、Condition条件

Condition是和重入锁关联使用,通过Lock接口的Condition newCondition()方法可以生成一个与当前重入锁绑定的Condition实例。Condition接口提供的方法如下:

await()方法会使当前线程等待,同时释放当前锁,当其他线程调用signal()/signalAll()方法时,线程可以获得锁并继续执行。调用该方法的线程可以响应中断,调处等待。

awaitUninterruptibly()方法,该方法与await()方法类似,只不过是不会在等待过程中响应中断。

singal()方法用于唤醒一个在等待中的线程。而signalAll()会唤醒所有在等待的线程。

在调用await()和signal()/signalAll()之前,线程需要先获得相应的重入锁,而且在调用await()时还需要捕获异常。同样的,调用await()方法之后,线程也会释放锁,而且在该线程被唤醒后也需要再次获得相关的重入锁才能继续执行。

如下示例:

public class ReentrantLockCondition implements Runnable{
	private static ReentrantLock lock=new ReentrantLock();
	private static Condition condition=lock.newCondition(); 
	public static void main(String[] args) throws InterruptedException {
		ReentrantLockCondition rlc=new ReentrantLockCondition();
		Thread t1=new Thread(rlc);
		t1.start();
		Thread.sleep(100);//主线程等待一会,否则主线程先获得锁就会导致signal()先执行,那t1就不会被唤醒了
		lock.lock();
		condition.signal();//先获得锁
		lock.unlock();
	}
	public void run() {		
		try{
			lock.lock();
			condition.await();//先加锁,还要捕获异常
			System.out.println("Thread is going on");
		}
		catch(InterruptedException e){
			e.printStackTrace();
		}
		finally{
			lock.unlock();
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值