多线程高并发编程(2) -- 可重入锁介绍和自定义
背景:
什么是 “可重入”?可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁。即可重入锁的作用就是为了避免死锁,java中synchronized和ReentrantLock都是可重入锁。
//synchronized 可重入锁 private void test() { // 第一次获得锁 synchronized (this) { while (true) { // 第二次获得同样的锁 synchronized (this) { System.out.println("ReentrantLock!"); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } //ReentrantLock可重入锁 Lock lock = new ReentrantLock(); private void test1() { lock.lock(); try { test2(); } finally { lock.unlock(); } } private void test2() { lock.lock(); try { System.out.println("ReentrantLock!"); } finally { lock.unlock(); } }
一.自定义不可重入锁
所谓不可重入锁,即若当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞。下面的线程执行test1()方法首先获取lock,接下来执行test2()方法就无法执行test2()中的逻辑,必须先释放锁。
// 不可重入锁 class Lock { //是否占用 private boolean isLocked = false; //使用锁 public synchronized void lock() { while (isLocked) {//已经占用 try { this.wait();//等待 } catch (InterruptedException e) { e.printStackTrace(); } } isLocked = true;//修改标识为已经占用 } //释放锁 public synchronized void unLock() { isLocked = false;//修改标识为未占用 notify();//唤醒等待线程 } } ============使用=========== Lock lock = new Lock(); public void test1() { lock.lock(); test2(); lock.unLock(); } private void test2() { lock.lock(); //... lock.unLock(); }
二.自定义可重入锁
流程:
- 定义锁占用标识、存储线程、线程锁持有数量;
- 使用锁:判断是否已经占用和当前线程是否不等于存储线程,如果条件符合进入等待,不符合则修改占用标识、存储线程为当前线程、线程锁数量+1;
- 释放锁:判断当前线程是否等于存储线程,条件符合则线程锁数量-1,当线程锁数量=0时,修改占用标识,唤醒等待线程,将存储线程置为null;
// 可重入锁 class ReLock{ //是否占用 private boolean isLocked = false; private Thread lockedBy = null; //存储线程 private int holdCount = 0; //使用锁 public synchronized void lock() throws InterruptedException { Thread t = Thread.currentThread(); while(isLocked && lockedBy != t) { wait(); } isLocked = true; lockedBy = t; holdCount ++; } //释放锁 public synchronized void unlock() { if(Thread.currentThread() == lockedBy) { holdCount --; if(holdCount ==0) { isLocked = false; notify(); lockedBy = null; } } } public int getHoldCount() { return holdCount; } } ==============使用=============== public class LockTest { ReLock lock = new ReLock(); public void test1() throws InterruptedException { lock.lock(); System.out.println(lock.getHoldCount()); test2(); lock.unlock(); System.out.println(lock.getHoldCount()); } //可重入 public void test2() throws InterruptedException { lock.lock(); System.out.println(lock.getHoldCount()); //................... lock.unlock(); System.out.println(lock.getHoldCount()); } public static void main(String[] args) throws InterruptedException { LockTest lockTest= new LockTest(); lockTest.test1(); Thread.sleep(1000); System.out.println(lockTest.lock.getHoldCount()); } }
作者:huangrenhui
欢迎任何形式的转载,但请务必注明出处。
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【码猿手】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【码猿手】。
限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。