全面解析CountDownLatch与ReentrantLock:揭示并行程序的多线程协作奥秘
2023-09-18 02:13:53
CountDownLatch
CountDownLatch是一个等待通知机制,允许一个或多个线程等待其他线程完成任务。它有一个计数器,当计数器为0时,所有等待的线程都会被唤醒。CountDownLatch通常用于以下场景:
- 等待所有线程完成任务后,再执行后续任务。
- 在所有线程完成任务之前,阻止主线程继续执行。
- 控制线程之间的同步。
CountDownLatch的用法非常简单,首先需要创建一个CountDownLatch对象,并指定计数器的初始值。然后,每个需要等待的线程都需要调用CountDownLatch的await()方法,该方法会使线程进入等待状态,直到计数器为0。当所有线程都调用了await()方法后,计数器将变为0,所有等待的线程都会被唤醒。
// 创建一个CountDownLatch对象,计数器初始值为5
CountDownLatch latch = new CountDownLatch(5);
// 创建5个线程,每个线程都调用CountDownLatch的await()方法
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 等待其他线程完成任务
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 执行后续任务
System.out.println("线程" + Thread.currentThread().getName() + "执行后续任务");
}
}).start();
}
// 主线程等待所有线程完成任务
latch.await();
// 执行后续任务
System.out.println("主线程执行后续任务");
ReentrantLock
ReentrantLock是一个锁机制,允许一个线程在同一时间独占访问共享资源。它与synchronized类似,但功能更加强大。ReentrantLock具有以下特点:
- 可重入性:一个线程可以多次获取同一把锁。
- 公平性:ReentrantLock提供了公平锁和非公平锁两种实现,公平锁保证线程获取锁的顺序与它们请求锁的顺序一致,非公平锁则没有这样的保证。
- 可中断性:ReentrantLock允许线程在等待锁时被中断。
ReentrantLock的用法也很简单,首先需要创建一个ReentrantLock对象,然后使用lock()方法获取锁,使用unlock()方法释放锁。在获取锁之前,线程可以调用tryLock()方法尝试获取锁,如果锁已经被其他线程获取,则tryLock()方法会立即返回false。
// 创建一个ReentrantLock对象
ReentrantLock lock = new ReentrantLock();
// 创建5个线程,每个线程都尝试获取锁
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
// 尝试获取锁,如果锁已经被其他线程获取,则立即返回false
if (lock.tryLock()) {
// 获取到锁后执行任务
System.out.println("线程" + Thread.currentThread().getName() + "获取到锁并执行任务");
// 释放锁
lock.unlock();
} else {
// 获取锁失败,执行其他任务
System.out.println("线程" + Thread.currentThread().getName() + "获取锁失败,执行其他任务");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
CountDownLatch与ReentrantLock的比较
CountDownLatch和ReentrantLock都是用于多线程编程的重要工具,但它们的功能不同。CountDownLatch用于等待所有线程完成任务后,再执行后续任务。ReentrantLock用于控制线程之间的同步,防止多个线程同时访问共享资源。
CountDownLatch和ReentrantLock都可以用来构建高性能并发程序,但它们适合的场景不同。CountDownLatch适合用于以下场景:
- 等待所有线程完成任务后,再执行后续任务。
- 在所有线程完成任务之前,阻止主线程继续执行。
- 控制线程之间的同步。
ReentrantLock适合用于以下场景:
- 控制线程之间的同步,防止多个线程同时访问共享资源。
- 实现互斥锁,防止多个线程同时执行同一块代码。
- 实现读写锁,允许多个线程同时读共享资源,但只能有一个线程写共享资源。
总结
CountDownLatch和ReentrantLock都是Java中用于多线程编程的重要工具。CountDownLatch用于等待所有线程完成任务后,再执行后续任务。ReentrantLock用于控制线程之间的同步,防止多个线程同时访问共享资源。通过合理使用CountDownLatch和ReentrantLock,可以构建高性能并发程序,提高程序的运行效率。