本篇主要介绍Java中显式锁的内容
- 在Java中,显式锁(
Explicit Lock
)提供了一种比synchronized
关键字更灵活的线程同步机制。Java的显式锁由java.util.concurrent.locks
包提供,最常用的显式锁是ReentrantLock
它是一个可重入锁,类似于synchronized
关键字,但提供了更多的功能和灵活性。;
1. 基本用法
- 用于对变量进行访问的保护,以确保在多线程环境下,线程运行是安全的;
- 具体做法:
//引入两个必要的库和里边的类 import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; …… //在设置变量之后,声明建立一个ReentrantLock类锁,并由Lock创建的对象接收 Lock lock = new ReentrantLock(); …… //在需要的时候获取锁 locks.lock(); try{ 代码块; }finally{ lock.unlock();//用finally的原因是确保在任何情况下都能释放锁,不至于出现死锁的情况。 } //此时,如果有多个方法都在使用相应的变量(体现在代码块中),将获取锁操作视作p操作,释放锁操作视为v操作,则下一个线程/方法在进行操作之前只能等前一个线程释放锁,即使数目上去了,结果也是如此。
2. 高级功能
2.1 可中断的锁获取
- 可以使用
ReentrantLock
尝试获取锁,并在等待锁的过程中响应中断(中断服务程序
); - 这个过程中使用
lock.lockInterruptibly()
方法,它也是ReentrantLock
提供的,但与.lock()
不同,它在获取锁的过程中会响应中断。如果当前线程在等待获取锁时被中断,那么该方法会抛出InterruptedException
异常。(等于是线程a和线程b,两者都使用了lockInterruptibly。当其中一个获取到锁后,引发中断,在等待锁的另一个线程被中断后会自动抛出InterruptedException异常直至锁被重新释放后解除中断
)。本质上不是用等待而是用中断的方式完成使用锁的排他,但得注意要有try--finally
块保证任何情况在都能正确释放锁,不然很快会死锁; - 实例:
//对中断锁的设置 public void safeIncrement() throws InterruptedException { lock.lockInterruptibly(); // 可中断地获取锁 try { count++; } finally { lock.unlock(); } } //一种情况举例 Counter counter = new Counter(); Runnable task = () -> { try { counter.safeIncrement(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.out.println("Thread was interrupted"); } }; Thread t1 = new Thread(task); Thread t2 = new Thread(task); t1.start(); t2.start();
2.2 尝试获取锁
- 使用
Locks
类的.trylock()
方法可以尝试获取锁,并在获取不到时立即返回;
try后边可以同时跟catch和finally,两者发挥的功能不同,一个是抛出异常的说明,另一个是兜底保证代码中是能被执行。
- 实例
public