• 作者:老汪软件技巧
  • 发表时间:2024-10-08 07:00
  • 浏览量:

1. 前序

在多线程编程中,线程同步是确保数据一致性和防止竞态条件的关键。Java 提供了多种用于线程同步的机制,以解决不同场景下的线程竞争问题。无论是最基本的 synchronized​ 关键字,还是更灵活的 ReentrantLock​、ReentrantReadWriteLock​,它们都为开发者提供了不同级别的锁和控制。

本文将逐一介绍 Java 中常见的同步机制,涵盖了 synchronized​、ReentrantLock​、Atomic​ 类等,同时给出每种机制的示例代码和适用场景,帮助你更好地理解并应用这些同步机制。

2. synchronized​2.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();
    }
}

java中线程同步的几种方法_线程同步java_

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()​ 可以实现线程之间的协调工作。