在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():释放锁