- 作者:老汪软件技巧
- 发表时间:2024-10-08 07:00
- 浏览量:
1. 前序
在多线程编程中,线程同步是确保数据一致性和防止竞态条件的关键。Java 提供了多种用于线程同步的机制,以解决不同场景下的线程竞争问题。无论是最基本的 synchronized 关键字,还是更灵活的 ReentrantLock、ReentrantReadWriteLock,它们都为开发者提供了不同级别的锁和控制。
本文将逐一介绍 Java 中常见的同步机制,涵盖了 synchronized、ReentrantLock、Atomic 类等,同时给出每种机制的示例代码和适用场景,帮助你更好地理解并应用这些同步机制。
2. synchronized2.1 synchronized 关键字
/**
* 示例类,演示如何使用 synchronized 方法进行线程同步
*/
public class SynchronizedMethodExample {
/** 共享计数器 */
private int counter = 0;
/**
* 同步递增计数器的方法,确保同一时刻只有一个线程可以执行
*/
public synchronized void increment() {
// 递增计数器
counter++;
// 输出当前线程和计数器的值
System.out.println(Thread.currentThread().getName() + " - Counter: " + counter);
}
/**
* 主程序入口,创建多个线程并运行
* @param args 默认参数
*/
public static void main(String[] args) {
SynchronizedMethodExample example = new SynchronizedMethodExample();
// 线程任务,调用 increment 方法
Runnable task = example::increment;
// 创建两个线程
Thread t1 = new Thread(task, "Thread 1");
Thread t2 = new Thread(task, "Thread 2");
// 启动线程
t1.start();
t2.start();
}
}
2.2 使用 synchronized 代码块
/**
* 示例类,演示如何使用 synchronized 代码块进行线程同步
*/
public class SynchronizedBlockExample {
/** 共享计数器 */
private int counter = 0;
/** 自定义锁对象 */
private final Object lock = new Object();
/**
* 同步递增计数器的方法,只锁定代码块
*/
public void increment() {
// 使用 synchronized 代码块确保锁定的粒度更小
synchronized (lock) {
counter++;
System.out.println(Thread.currentThread().getName() + " - Counter: " + counter);
}
}
/**
* 主程序入口,创建多个线程并运行
* @param args 默认参数
*/
public static void main(String[] args) {
SynchronizedBlockExample example = new SynchronizedBlockExample();
Runnable task = example::increment;
Thread t1 = new Thread(task, "Thread 1");
Thread t2 = new Thread(task, "Thread 2");
t1.start();
t2.start();
}
}
3. ReentrantLock
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 示例类,演示如何使用 ReentrantLock 进行线程同步
*/
public class LockExample {
/** 共享计数器 */
private int counter = 0;
/** ReentrantLock 实例 */
private final Lock lock = new ReentrantLock();
/**
* 同步递增计数器的方法,手动加锁和解锁
*/
public void increment() {
// 获取锁
lock.lock();
try {
// 递增计数器
counter++;
// 输出当前线程和计数器的值
System.out.println(Thread.currentThread().getName() + " - Counter: " + counter);
} finally {
// 确保锁在最后被释放
lock.unlock();
}
}
/**
* 主程序入口,创建多个线程并运行
* @param args 默认参数
*/
public static void main(String[] args) {
LockExample example = new LockExample();
Runnable task = example::increment;
Thread t1 = new Thread(task, "Thread 1");
Thread t2 = new Thread(task, "Thread 2");
t1.start();
t2.start();
}
}
4. ReentrantReadWriteLock
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 示例类,演示如何使用 ReentrantReadWriteLock 进行线程同步
*/
public class ReadWriteLockExample {
/** 共享计数器 */
private int counter = 0;
/** ReentrantReadWriteLock 实例 */
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
/**
* 获取写锁并递增计数器
*/
public void increment() {
// 获取写锁
lock.writeLock().lock();
try {
// 递增计数器
counter++;
System.out.println(Thread.currentThread().getName() + " - Write Counter: " + counter);
} finally {
// 释放写锁
lock.writeLock().unlock();
}
}
/**
* 获取读锁并读取计数器
* @return 计数器值
*/
public int getCounter() {
// 获取读锁
lock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " - Read Counter: " + counter);
return counter;
} finally {
// 释放读锁
lock.readLock().unlock();
}
}
/**
* 主程序入口,创建多个线程并运行
* @param args 默认参数
*/
public static void main(String[] args) {
ReadWriteLockExample example = new ReadWriteLockExample();
Runnable writeTask = example::increment;
Runnable readTask = example::getCounter;
Thread t1 = new Thread(writeTask, "Writer Thread");
Thread t2 = new Thread(readTask, "Reader Thread");
t1.start();
t2.start();
}
}
5. Atomic 类
import java.util.concurrent.atomic.AtomicInteger;
/**
* 示例类,演示如何使用 AtomicInteger 进行线程同步
*/
public class AtomicExample {
/** 线程安全的 AtomicInteger */
private AtomicInteger counter = new AtomicInteger(0);
/**
* 原子性递增计数器的方法
*/
public void increment() {
// 原子递增
int newValue = counter.incrementAndGet();
System.out.println(Thread.currentThread().getName() + " - Counter: " + newValue);
}
/**
* 主程序入口,创建多个线程并运行
* @param args 默认参数
*/
public static void main(String[] args) {
AtomicExample example = new AtomicExample();
Runnable task = example::increment;
Thread t1 = new Thread(task, "Thread 1");
Thread t2 = new Thread(task, "Thread 2");
t1.start();
t2.start();
}
}
6. CyclicBarrier
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* 示例类,演示如何使用 CyclicBarrier 实现线程同步
*/
public class CyclicBarrierExample {
/** CyclicBarrier 实例,等待 3 个线程 */
private final CyclicBarrier barrier = new CyclicBarrier(3, () -> {
// 所有线程到达屏障后执行的操作
System.out.println("All threads have reached the barrier. Barrier action executed.");
});
/**
* 线程任务,等待屏障点并继续执行
*/
public void performTask() {
System.out.println(Thread.currentThread().getName() + " is waiting at the barrier");
try {
// 等待其他线程到达屏障点
barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " has crossed the barrier");
}
/**
* 主程序入口,创建多个线程并运行
* @param args 默认参数
*/
public static void main(String[] args) {
CyclicBarrierExample example = new CyclicBarrierExample();
Thread t1 = new Thread(example::performTask, "Thread 1");
Thread t2 = new Thread(example::performTask, "Thread 2");
Thread t3 = new Thread(example::performTask, "Thread 3");
t1.start();
t2.start();
t3.start();
}
}
7. Object 的 wait() 和 notify() 方法
/**
* 示例类,演示如何使用 wait() 和 notify() 进行线程同步
*/
public class WaitNotifyExample {
/** 自定义锁对象 */
private final Object lock = new Object();
/** 标志位,表示是否已经生产了数据 */
private boolean isProduced = false;
/**
* 生产者方法,等待消费者消费后生产新数据
* @throws InterruptedException 当线程被中断时抛出异常
*/
public void produce() throws InterruptedException {
synchronized (lock) {
// 如果已经生产了数据,等待消费者消费
while (isProduced) {
lock.wait();
}
// 生产数据
System.out.println(Thread.currentThread().getName() + " produced data.");
isProduced = true;
// 通知消费者可以消费数据了
lock.notify();
}
}
/**
* 消费者方法,等待生产者生产数据并进行消费
* @throws InterruptedException 当线程被中断时抛出异常
*/
public void consume() throws InterruptedException {
synchronized (lock) {
// 如果还没有生产数据,等待生产者生产
while (!isProduced) {
lock.wait();
}
// 消费数据
System.out.println(Thread.currentThread().getName() + " consumed data.");
isProduced = false;
// 通知生产者可以继续生产数据了
lock.notify();
}
}
/**
* 主程序入口,创建生产者和消费者线程并运行
* @param args 默认参数
*/
public static void main(String[] args) {
WaitNotifyExample example = new WaitNotifyExample();
// 创建生产者线程
Thread producer = new Thread(() -> {
try {
for (int i = 0; i < 5; i++) {
example.produce();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "Producer");
// 创建消费者线程
Thread consumer = new Thread(() -> {
try {
for (int i = 0; i < 5; i++) {
example.consume();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "Consumer");
producer.start();
consumer.start();
}
}
8. 总结
Java 提供了多种用于线程同步的机制,包括 synchronized、ReentrantLock、ReentrantReadWriteLock、Atomic 类、CyclicBarrier 以及 Object 的 wait()/notify()。每种方式都有其适用场景和优缺点。对于简单的同步需求,synchronized 是一种直接而有效的选择;对于复杂的并发控制,Lock 提供了更灵活的锁机制;而 wait() 和 notify() 可以实现线程之间的协调工作。