《并发编程》--10.重入锁

在jdk5的时代,重入锁可以完全替代synchronized。但从jdk6开始对synchronized做了大量的优化,使两者在性能上差距不大。

以下是冲入锁的一段简单代码

public class ReenterLock implements Runnable {
	public static ReentrantLock lock = new ReentrantLock();
	public static int i  = 0;

	@Override
	public void run() {
		for(int j = 0;j<1000000;j++){
			lock.lock();  //加锁
			try {
				i++;
			}finally{
				lock.unlock(); //释放锁
			} 
		}
	}
	public static void main(String[] args) throws InterruptedException {
		ReenterLock ti = new ReenterLock();
		Thread t1 = new Thread(ti);
		Thread t2 = new Thread(ti);
		t1.start();
		t2.start();
		t1.join();
		t2.join();
		System.out.println(i);
	}

}


从代码中可以看出:和synchronized相比,重入锁有着明显的操作过程,研发人员必须手动操作,合适加锁,合适释放锁。冲入锁对逻辑控制灵活性远远高于synchronized。

但是有一点必须注意:退出时必须释放锁,否则其他线程将无法继续访问临界区。,

重入锁对单线程是可以反复进入的,并不支持多线程,如下 例子,只修改run方法

	@Override
	public void run() {
		for(int j = 0;j<1000000;j++){
			lock.lock();  //加锁
			lock.lock();  //加锁
			try {
				i++;
			}finally{
				lock.unlock(); //释放锁
				lock.unlock(); //释放锁
			} 
		}
	}

同一线程在第二次获得锁时,将会和自己产生死锁。反之,释放锁的次数少了,那么相当于其他线程继续持有这个锁,其他线程将无法进入临界区。


1.中断响应

对于synchronized来说,如果一个线程在等待所,只有两个情况,要么持有锁继续执行,要不在持续等待中。

而对于重入锁来说:还多了另一种选择,等等待过程中,取消锁的等待。这种情况对于处理死锁有一定帮助。代码如下

public class IntLock implements Runnable{
	public static ReentrantLock lock1 = new ReentrantLock();
	public static ReentrantLock lock2 = new ReentrantLock();
	int lock ;
	/**
	 * 控制加锁顺序,方便构成死锁
	 */
	public IntLock(int lock){
		this.lock = lock;
	}
	@Override
	public void run() {
		try {
			if(lock ==1){
				lock1.lockInterruptibly();
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					lock2.lockInterruptibly();
				}
			}
			else{
				lock2.lockInterruptibly();
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					lock1.lockInterruptibly();
				}
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally {
			if(lock1.isHeldByCurrentThread());{
				lock1.unlock();
			}
			if(lock2.isHeldByCurrentThread());{
				lock2.unlock();
			}
			System.out.println(Thread.currentThread().getId()+" : 线程退出 ");
		}
		
	}		

	
	public static void main(String[] args)throws InterruptedException{
		IntLock i1 = new IntLock(1);
		IntLock i2 = new IntLock(2);
		Thread t1 = new Thread(i1);
		Thread t2 = new Thread(i2);
		t1.start();t2.start();
		Thread.sleep(1000);
		t2.interrupt();//中断其中一个线程
		
	}
}

2.锁申请等待限时

tryLock()方法接受两个参数,第1个表示等待时长,第二个表示计量单位。

表示在等这个锁的请求中,最多等待2秒,如果超过2秒没有获得锁,将返回false。代码如下

public class TimeLock implements Runnable{
	public static ReentrantLock lock = new ReentrantLock();

	@Override
	public void run() {
		try{
			if(lock.tryLock(5,TimeUnit.SECONDS)){//第一个表示等待时长,第二个表示计量单位
				Thread.sleep(6000);
			}else{
				System.out.println("获得所失败!!!");
			}
		}catch(InterruptedException e){
			e.printStackTrace();
		}finally {
			if (lock.isHeldByCurrentThread()) 
			lock.unlock();
		}
		
	}		

	
	public static void main(String[] args)throws InterruptedException{
		TimeLock i1 = new TimeLock();
		Thread t1 = new Thread(i1);
		Thread t2 = new Thread(i1);
		t1.start();t2.start();
		
		
	}
}

ReentrantLock的重要方法整理

1.lock():获得锁,如果所已经被占用,等待

2.lock.lockInterruptibly( );:获得所,有限响应中断

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

4.lock.tryLock(5,TimeUnit.SECONDS):在指定时间获得所

5.unlock():释放锁



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值