什么是 “可重入”?可重入就是说某个线程已经获得某个锁,可以再次获取锁而不会出现死锁。即可重入锁的作用就是为了避免死锁,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;在此我向大家推荐一个架构学习交流圈。交流学习指导伪鑫:1253431195(里面有大量的面试题及答案)里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多
- 释放锁:判断当前线程是否等于存储线程,条件符合则线程锁数量-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());
}
}