ReentrantLock
Sync是隐式锁。Lock是显示锁
ReentrantLock是Lock的默认实
概念:
1.可重入锁:可重入锁是指同一个线程可以多次获得同一把锁;ReentrantLock和关键字Synchronized都是可重入锁
2.可中断锁:可中断锁时子线程在获取锁的过程中,是否可以相应线程中断操作 synchronized 是不可中断的。ReentrantLock是可中断的
3.公平锁和非公平锁:公平锁是指多个线程尝试获取同一把锁的时候,获取锁的顺序按照线程到达的先后顺序获取,而不是随机插队的方式获取。synchronized是
非公平锁,而ReentrantLock是两种都可以实现,不过默认是非公平锁.
示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantLock;
/**
* 主类ReentrantLockMain展示了使用ReentrantLock实现线程安全的工资扣除示例。
*/
public class ReentrantLockMain {
/**
* 工资变量,初始化为500000。此变量的修改需要线程安全的操作。
*/
private static Integer salary = 500000;
/**
* 使用ReentrantLock实例作为线程同步的机制。
*/
private static ReentrantLock lock = new ReentrantLock();
/**
* SalaryRunnable内部类实现了Runnable接口,用于扣除工资的线程任务。
*/
static class SalaryRunnable implements Runnable {
/**
* 执行工资扣除操作。
* 使用lock.lock()获取锁,确保在同一时刻只有一个线程可以执行工资扣除操作,
* 以保证线程安全。
*/
@Override
public void run() {
try {
lock.lock(); // 获取锁
salary = salary - 1000; // 执行工资扣除操作
System.out.println("salary:"+salary);
} catch (Exception ex) {
System.out.println(ex.getMessage()); // 捕获并打印异常信息
} finally {
if(lock.isHeldByCurrentThread()) { //检查当前线程是否持有锁。
lock.unlock(); // 无论是否发生异常,最终都要释放锁
}
}
}
}
/**
* 程序入口主方法。
* 创建一个线程池,并提交一个SalaryRunnable任务进行执行。
* @param args 命令行参数
*/
public static void main(String[] args) {
ExecutorService threadPool = Executors.newCachedThreadPool(); // 创建线程池
for(int i=0;i<5;i++) {
SalaryRunnable task = new SalaryRunnable(); // 创建工资扣除任务
threadPool.execute(task); // 提交任务给线程池执行
}
threadPool.shutdown();
}
}
tryLock
申请锁等待限时,在获取锁的时间不确定的情况下,synchronized关键字获取锁的过程中,只能等待其他线程把锁释放之后才能够有机会获取到锁。所以获
取锁的时间有长有短,充满了不确定性。如果获取锁的时间能够设置超时时间,无法判断。
ReentrantLock提供了获取锁限时等待的方法 tryLock(),可以选择传入时间参数,表示等待指定的时间,无参则表示立即返回锁申请的结果:true表示获取
锁成功,false表示获取锁失败。
示例1:
import java.util.concurrent.locks.ReentrantLock;
/**
* TryLockMain 类用于演示使用 ReentrantLock 的 tryLock 方法。
*/
public class TryLockMain {
/**
* 全局的 ReentrantLock 实例,用于演示线程之间的锁竞争。
*/
private static ReentrantLock lock = new ReentrantLock();
/**
* T 类继承自 Thread,用于具体执行线程任务。
*/
public static class T extends Thread {
/**
* 构造函数,初始化线程名称。
*
* @param name 线程名称。
*/
public T(String name) {
super(name);
}
/**
* 线程的执行逻辑。
*/
@Override
public void run() {
try {
// 尝试使用 tryLock 方法获取锁。
System.out.println("TryLock");
if (!lock.tryLock()) { // 如果锁被占用,返回false。
System.out.println("获取锁失败");
return;
} else {
System.out.println("获取锁成功");
// 在获取锁成功后,使用 synchronized 关键字确保线程安全。
synchronized (this) {
// 这里使用 getName() 直接打印线程名称。
this.getName().toString(); // 这里使用的是this.getName().toString(),而不是this.getName().toUpperCase()。
}
// 执行完任务后释放锁。
System.out.println(" lock.unlock()");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 确保在任何情况下都释放锁。
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}
/**
* 程序入口,创建并启动两个线程,演示锁的获取和释放。
*
* @param args 命令行参数。
* @throws Exception 如果线程的等待发生异常。
*/
public static void main(String[] args) throws Exception {
T t1 = new T("name:T1 ");
T t2 = new T("name:T2 ");
t1.start();
t2.start();
// 等待两个线程执行完毕。
t1.join();
t2.join();
}
}
示例2:
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* TryLockMain 类用于演示使用 ReentrantLock 的 tryLock 方法。
*/
public class TryLockMain {
/**
* 全局的 ReentrantLock 实例,用于演示线程之间的锁竞争。
*/
private static ReentrantLock lock = new ReentrantLock();
/**
* T 类继承自 Thread,用于具体执行线程任务。
*/
public static class T extends Thread {
/**
* 构造函数,初始化线程名称。
*
* @param name 线程名称。
*/
public T(String name) {
super(name);
}
/**
* 线程的执行逻辑。
*/
@Override
public void run() {
try {
// 尝试使用 tryLock 方法获取锁。
System.out.println("TryLock");
if (!lock.tryLock()) { // 如果锁被占用,返回false。
System.out.println("获取锁失败");
return;
} else {
System.out.println("获取锁成功");
// 在获取锁成功后,使用 synchronized 关键字确保线程安全。
synchronized (this) {
// 这里使用 getName() 直接打印线程名称。
this.getName().toString(); // 这里使用的是this.getName().toString(),而不是this.getName().toUpperCase()。
}
// 执行完任务后释放锁。
System.out.println(" lock.unlock()");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 确保在任何情况下都释放锁。
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}
/**
* 程序入口,创建并启动两个线程,演示锁的获取和释放。
*
* @param args 命令行参数。
* @throws Exception 如果线程的等待发生异常。
*/
public static void main(String[] args) throws Exception {
T t1 = new T("name:T1 ");
T1 t2 = new T1("name:T2 ");
t1.start();
t2.start();
// 等待两个线程执行完毕。
t1.join();
t2.join();
}
public static class T1 extends Thread {
public T1(String name) {
super(name);
}
@Override
public void run() {
try {
System.out.println("System.currentTimeMillis(): " + "+" + this.getName() + "开始获取锁!");
tryLock();
if (lock.tryLock(2, TimeUnit.SECONDS)) { // lock
System.out.println("System.currentTimeMillis(): " + "+" + this.getName() + "获得锁!");
try {
Thread.sleep(500L);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println("System.currentTimeMillis(): " + "+" + this.getName() + "未能获取到锁!");
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
private synchronized void tryLock() throws InterruptedException {
while (!lock.tryLock( 2, TimeUnit.SECONDS)) { // lock
System.out.println("System.currentTimeMillis(): " + "+" + this.getName() + "尝试获取锁中...");
}
}
}
}