重入锁 |
重入锁可以完全替代synchronized关键字,jdk5的早期版本中,重入锁的性能远远好于synchronized,在jdk6之后,jdk在synchronized上做了大量的优化,使得两者的性能差距并不大。
·重入锁简单使用 |
method1拿到锁之后执行业务代码,method2需要等待method1释放锁资源,从而保证了安全性
public class UseReentrantLock {
private Lock lock = new ReentrantLock();
public void method1(){
try {
lock.lock();
System.out.println("当前线程:" + Thread.currentThread().getName() + "进入method1...");
Thread.sleep(1000);
System.out.println("当前线程:" + Thread.currentThread().getName() + "退出method1...");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public void method2(){
try {
lock.lock();
System.out.println("当前线程:" + Thread.currentThread().getName() + "进入method2..");
Thread.sleep(2000);
System.out.println("当前线程:" + Thread.currentThread().getName() + "退出method2..");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
public static void main(String[] args) {
final UseReentrantLock ur = new UseReentrantLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
ur.method1();
ur.method2();
}
},"t1");
t1.start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
执行的结果如下:
当前线程:t1进入method1...
当前线程:t1退出method1...
当前线程:t1进入method2..
当前线程:t1退出method2..
·中断响应 |
使用synchronized,对于一个线程在等待锁,要么就获得了锁,可以执行业务代码,要么就没获得到锁,从而必须等待。
使用重入锁,线程可以被中断,也就是在等待锁的过程中,程序可以根据需要取消对锁的请求
将上述方法改造,线程t1和线程t2会产生死锁,这时我们将t2中断,从而t1线程会正常执行:
public class UseReentrantLock {
public static ReentrantLock lock1 = new ReentrantLock();
public static ReentrantLock lock2 = new ReentrantLock();
public void method1(){
try {
lock1.lockInterruptibly();
System.out.println("当前线程:" + Thread.currentThread().getName() + "进入method1...");
Thread.sleep(1000);
lock2.lockInterruptibly();
System.out.println("当前线程:" + Thread.currentThread().getName() + "退出method1...");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
if(lock1.isHeldByCurrentThread()){
lock1.unlock();
}
if(lock2.isHeldByCurrentThread()){
lock2.unlock();
}
}
}
public void method2(){
try {
lock2.lockInterruptibly();
System.out.println("当前线程:" + Thread.currentThread().getName() + "进入method2..");
Thread.sleep(2000);
lock1.lockInterruptibly();
System.out.println("当前线程:" + Thread.currentThread().getName() + "退出method2..");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
if(lock1.isHeldByCurrentThread()){
lock1.unlock();
}
if(lock2.isHeldByCurrentThread()){
lock2.unlock();
}
}
}
public static void main(String[] args) {
final UseReentrantLock ur = new UseReentrantLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
ur.method1();
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
ur.method2();
}
},"t2");
t1.start();
t2.start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.interrupt();
}
}
·锁申请等待限时 |
要避免死锁,另一种方法就是限时等待,在一定时间内还没有拿到锁,那就自动放弃,可以使用tryLock()进行限时等待:
public class TimeLock implements Runnable{
public static ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
try {
if(lock.tryLock(5, TimeUnit.SECONDS)){
System.out.println(Thread.currentThread().getName() + ": get lock success");
Thread.sleep(6000);
}else{
System.out.println(Thread.currentThread().getName() + ": get lock failed");
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
public static void main(String[] args) {
TimeLock t1 = new TimeLock();
Thread t = new Thread(t1);
Thread t2 = new Thread(t1);
t.start();
t2.start();
}
}
执行结果:
Thread-0: get lock success
Thread-1: get lock failed
线程t1获得锁成功后,线程会睡眠6s,线程t2再去获得锁时,在5s内t1线程 还未释放,所以t2线程获取锁失败。
·公平锁 |
一般锁的申请都是非公平的,当锁可用时,多个线程同时去争抢这个锁资源,那么哪个线程可以获得到锁是不确定的
public class FairLock implements Runnable{
public static ReentrantLock fairLock = new ReentrantLock(true);
@Override
public void run() {
while (true){
try {
fairLock.lock();
System.out.println(Thread.currentThread().getName() + " 获得锁");
} finally {
fairLock.unlock();
}
}
}
public static void main(String[] args) {
FairLock r1 = new FairLock();
Thread t1 = new Thread(r1,"t1");
Thread t2 = new Thread(r1,"t2");
t1.start();
t2.start();
}
}
当参数为true时,是公平锁,当参数为false时,是非公平锁,执行结果如下:
t1 获得锁
t2 获得锁
t1 获得锁
t2 获得锁
t1 获得锁
t2 获得锁
...
实现原理 |
重入锁是对一个线程来讲的,一个线程获取了锁之后,可以循环递归的获取同一个锁(计数+1),当释放一次锁时,即将计数-1,当减为0,会立即释放锁,其他线程才能获取
参考链接如下:https://blog.csdn.net/yanyan19880509/article/details/52345422