Java 中使用同步线程的方式

Java 中使用同步线程的方式

1. 前序

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

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

接下来,我们将详细讨论并演示每种方式的使用方法。

2. synchronized

2.1 synchronized 关键字

描述:Java 中最基础的同步机制就是 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 方法,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

描述:ReentrantLock 是 Lock 接口的一个常用实现,它提供了更灵活的锁定机制,允许手动加锁和解锁。

示例代码:

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

描述: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 类

描述:Atomic 类位于 java.util.concurrent.atomic 包内,提供了常见的原子操作类(如 AtomicInteger),用于在无锁的情况下对单一变量进行线程安全的操作。

示例代码:

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

描述: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() 方法

描述:Object 类的 wait()、notify() 和 notifyAll() 方法允许线程在某个条件下进行等待和唤醒。与 synchronized 搭配使用,可以实现类似于信号量的功能。

示例代码:

/**

* 示例类,演示如何使用 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() 可以实现线程之间的协调工作。

相关推荐

2014年巴西世界杯精彩回顾与冠军球队排名分析2025-06-15 06:49:13浏览次数: 次返回列表
林心如属什么生肖什么星座,林心如属什么生肖多少岁
365速发国际welcome

林心如属什么生肖什么星座,林心如属什么生肖多少岁

📅 07-26 👁️ 1364
聚的笔顺在田字格正确的写法
det365娱乐场

聚的笔顺在田字格正确的写法

📅 07-13 👁️ 770
【策划有话说】全段位开放五排 中低段上分体验优化
深圳市茁壮网络股份有限公司怎么样?
det365娱乐场

深圳市茁壮网络股份有限公司怎么样?

📅 07-24 👁️ 7706
26个字母的z怎么样读?英语字母发音教学!
det365娱乐场

26个字母的z怎么样读?英语字母发音教学!

📅 07-28 👁️ 289
Mac下command+R和shift+command+R的区别,在线恢复模式的选择
王者荣耀省标是永久的吗 金标是不是永久显示
det365娱乐场

王者荣耀省标是永久的吗 金标是不是永久显示

📅 07-25 👁️ 8400
哑铃卧推:如何安全的拿起,放下哑铃?
det365娱乐场

哑铃卧推:如何安全的拿起,放下哑铃?

📅 06-30 👁️ 5631