【Java】jdk 中的可重入锁
jdk 中的可重入锁有
synchronized和ReentrantLock
可重入锁,也称为递归锁。一个持有锁的线程,在释放锁之前,如果再次访问了该同步锁的其他方法,这个线程不需要再次竞争锁,只需要记录重入次数。重入锁的设计目的是为了解决死锁的问题
p.s. 以 synchronized 举例,若一个 synchronized 方法1 调用 synchronized 方法2,两方法的锁都是同一个,则某线程执行方法1时,会一并执行方法2,并不会因为方法1拿了锁,方法2没有而不执行
synchronized
synchronized 有四种用法:
- 修饰实例方法
- 修饰静态方法
- 修饰实例方法的代码块
- 修饰静态方法的代码块
synchronized 代码块的参数:this表示当前类对象(静态方法中不能用);xxx.class表示类本身;还可以传入其他参数
// 修饰实例方法:锁的是类对象
public synchronized void printHello() {
System.out.println("hello");
}
// 修饰静态方法:锁的是类本身
public static synchronized void printHi() {
System.out.println("hi");
}
// 修饰实例方法的代码块
public void printHello() {
synchronized (this) {
System.out.println("hello");
}
}
// 修饰静态方法的代码块
public static void printHi() {
synchronized (MultithreadDemo.class) {
System.out.println("hello");
}
}
ReentrantLock
ReentrantLock 类实现了 Lock接口,除此以外还有其他实现类👇

常用方法
lock():等待锁,无视中断lockInterruptibly():等待锁,考虑中断。中断会抛出 InterruptedExceptiontryLock(long timeout, TimeUnit unit):指定时间等待锁,考虑中断。指定时间内获得锁返回 true,否则 false,中断会抛出 InterruptedExceptiontryLock():直接获取锁。成功 true,否则 false,相当于tryLock(0, TimeUnit unit)unlock():解锁。必须有持有锁的线程执行,否则抛出 IllegalMonitorStateException- 为了避免死锁,
unlock()最好放在 finally 中 - ReentrantLock 是可重入锁,因此一个线程可能多次加锁,但是
unlock()执行一次解锁一次,因此加几次锁,就要解锁几次
- 为了避免死锁,
lock() 和 unlock() 的简单使用👇
private Lock lock = new ReentrantLock();
public void run () {
lock.lock();
try {
for (int i = 0; i < 5; i++)
System.out.println(Thread.currentThread().getName() + ":" + i);
} finally {
lock.unlock();
}
}
lock()、lockInterruptibly()、tryLock(long timeout, TimeUnit unit) 在线程中断情况下的表现👇
ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lock();
System.out.println("t1拿到锁");
Thread.sleep(1000L);
System.out.println("t1执行结束");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
boolean flag = true;
try {
System.out.println("t2等待拿锁");
// ****************** start **********************
// lock.lock();
// lock.lockInterruptibly();
flag = lock.tryLock(200, TimeUnit.MILLISECONDS);
// ****************** end **********************
if (flag) {
System.out.println("t2拿到锁");
System.out.println("t2执行结束");
} else {
System.out.println("指定时间内没有拿到锁,over");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (flag) {
lock.unlock();
}
}
}
});
t1.start();
// 保证 t1 拿到锁
Thread.sleep(10L);
t2.start();
// 保证 t2 在等待锁
Thread.sleep(10L);
// 若隐藏线程中断语句,t2 正常等待锁 或 指定时间内等待
t2.interrupt();
// 在测试类中需要保持运行一会
Thread.sleep(2000L);
其他方法
- int getHoldCount():当前锁的加锁次数,如果无线程持有锁就返回0
- int getQueueLength():当前竞争此锁队列长度
- int getWaitQueueLength(Condition condition):当前锁等待队列长度。需要与Condition联合使用
- boolean isFair():是否是公平锁
- boolean isLocked():当前锁是否处于锁定状态
- boolean isHeldByCurrentThread():当前锁是否被当前线程持有
- boolean hasWaiters(Condition condition):当前condition是否有线程在等待,需要与Condition联合使用
- boolean hasQueuedThread(Thread thread):目标线程是否在这个锁的竞争队列中
- boolean hasQueuedThreads():是否有线程在当前锁的竞争队列中
两者区别


浙公网安备 33010602011771号