返回

全面解析CountDownLatch与ReentrantLock:揭示并行程序的多线程协作奥秘

后端

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,可以构建高性能并发程序,提高程序的运行效率。