ReentrantLock是重入锁,它与synchronized很像,它是synchronized的加强版,因为它具有一些synchronized没有的功能。
下面我们看看两者的区别:
synchronized具有一定的局限性:
- 当线程尝试获取锁的时候,如果获取不到锁会一直阻塞;
- 如果获取锁的线程进入休眠或者阻塞,除非当前线程异常,否则其他线程尝试获取锁必须一直等待;
- 是非公平的。
而ReentrantLock实现了AQS,可以完成下列功能:
- 可中断响应;
- 锁申请等待限时;
- 公平锁;
- 与Condition一起使用,实现synchronized与wait/notify的功能。
引入几个概念:
提到ReentrantLock,我们不得不明白几个概念:
- 可重入锁。可重入锁是指同一个线程可以多次获取同一把锁。ReentrantLock和synchronized都是可重入锁。
- 可中断锁。可中断锁是指线程尝试获取锁的过程中,是否可以响应中断。synchronized是不可中断锁,ReentrantLock则提供了中断功能。
- 公平锁与非公平锁。公平锁是指多个线程必须按顺序,不许插队。非公平锁允许插队。synchronized是非公平锁,而ReentrantLock的默认实现是非公平锁,但是也可以设置为公平锁。
- CAS,在前面已经提到。
使用示例
具体用法通过简单代码通过代码演示:
import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockDemo implements Runnable { static ReentrantLock lock = new ReentrantLock(); static int count = 0; @Override public void run() { for (int i = 0; i < 10000; i++) { lock.lock(); try { count++; } finally { lock.unlock(); } } } public static void main(String[] args) { ReentrantLockDemo r = new ReentrantLockDemo(); Thread t1 = new Thread(r); Thread t2 = new Thread(r); t1.start(); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(count); //结果输出:20000 } }
通过ReentrantLock解决死锁问题:
import java.util.concurrent.locks.ReentrantLock; public class KillDeadlockDemo implements Runnable { static ReentrantLock lock1 = new ReentrantLock(); static ReentrantLock lock2 = new ReentrantLock(); int lock; public KillDeadlockDemo(int lock) { super(); this.lock = lock; } @Override public void run() { try { if (lock == 1) { lock1.lockInterruptibly(); Thread.sleep(500); lock2.lockInterruptibly(); } else { lock2.lockInterruptibly(); Thread.sleep(500); lock1.lockInterruptibly(); } } catch (InterruptedException e) { } finally { if (lock1.isHeldByCurrentThread()) { lock1.unlock(); } if (lock2.isHeldByCurrentThread()) { lock2.unlock(); } System.out.println(Thread.currentThread().getName() + "退出!"); } } public static void main(String[] args) { KillDeadlockDemo kdd1 = new KillDeadlockDemo(1); KillDeadlockDemo kdd2 = new KillDeadlockDemo(2); Thread t1 = new Thread(kdd1); Thread t2 = new Thread(kdd2); t1.start(); t2.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } t2.interrupt(); /* *结果输出: *Thread-1退出! *Thread-0退出! */
}
}
使用 tryLock()或者tryLock(long timeout, TimeUtil unit) 方法进行一次限时的锁等待,也可以解决死锁问题:
import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; public class TryLockDemo implements Runnable { static ReentrantLock lock = new ReentrantLock(); @Override public void run() { try { if (lock.tryLock(1, TimeUnit.SECONDS)) { Thread.sleep(1100); } else { System.out.println(Thread.currentThread().getName() + "获取锁失败!释放"); } } catch (InterruptedException e) { e.printStackTrace(); } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } public static void main(String[] args) { TryLockDemo td = new TryLockDemo(); Thread thread1 = new Thread(td); Thread thread2 = new Thread(td); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } //结果输出:Thread-1获取锁失败!释放 } }
公平锁演示:
import java.util.concurrent.locks.ReentrantLock; public class FairLockDemo implements Runnable { static ReentrantLock lock = new ReentrantLock(true); @Override public void run() { while (true) { try { lock.lock(); System.out.println(Thread.currentThread().getName() + " get lock"); Thread.sleep(1000); } catch (InterruptedException e) { } finally { lock.unlock(); } } } public static void main(String[] args) { FairLockDemo fld = new FairLockDemo(); Thread t1 = new Thread(fld); Thread t2 = new Thread(fld); Thread t3 = new Thread(fld); t1.start(); t2.start(); t3.start(); /* *Thread-0 get lock *Thread-1 get lock *Thread-2 get lock *Thread-0 get lock *Thread-1 get lock *Thread-2 get lock *.......... */ } }
浅谈原理
请转到:https://www.cnblogs.com/ericz2j/p/13445822.html