Java一分钟之-并发编程:线程间通信(Phaser, CyclicBarrier, Semaphore)

简介: 【5月更文挑战第19天】Java并发编程中,Phaser、CyclicBarrier和Semaphore是三种强大的同步工具。Phaser用于阶段性任务协调,支持动态注册;CyclicBarrier允许线程同步执行,适合循环任务;Semaphore控制资源访问线程数,常用于限流和资源池管理。了解其使用场景、常见问题及避免策略,结合代码示例,能有效提升并发程序效率。注意异常处理和资源管理,以防止并发问题。

在Java并发编程中,线程间的协作与通信是实现复杂并发逻辑的关键。Phaser, CyclicBarrier, 和 Semaphore 是Java并发包提供的强大工具,它们分别适用于不同的同步需求。本文将深入浅出地介绍这三个组件的使用场景、常见问题及避免策略,并附上代码示例。
image.png

1. Phaser - 阶段性任务协调器

介绍

Phaser 是一个灵活的同步屏障,支持动态注册和取消注册参与者,适用于有多个阶段的任务执行流程。

常见问题与避免策略

  • 问题:过度依赖动态注册,导致阶段结束条件难以预测。
  • 避免:明确每个阶段的预期参与者数量,适时使用arriveAndDeregister方法。

示例

import java.util.concurrent.Phaser;

public class PhaserDemo {
   
   
    public static void main(String[] args) {
   
   
        Phaser phaser = new Phaser(1); // 初始参与者为1(主线程)

        for (int i = 0; i < 3; i++) {
   
   
            new Thread(() -> {
   
   
                System.out.println(Thread.currentThread().getName() + " arrived.");
                phaser.arriveAndAwaitAdvance(); // 到达并等待所有到达
                System.out.println(Thread.currentThread().getName() + " continuing.");
            }, "Thread-" + (i+1)).start();
        }

        phaser.arriveAndDeregister(); // 主线程到达并注销
    }
}

2. CyclicBarrier - 循环屏障

介绍

CyclicBarrier 允许一组线程相互等待,直到达到某个屏障点后一起继续执行。它支持重置和重复使用,适用于循环执行的任务。

常见问题与避免策略

  • 问题:忘记处理BrokenBarrierException,导致程序意外终止。
  • 避免:在run()方法中捕获并适当处理此异常。

示例

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierDemo {
   
   
    public static void main(String[] args) {
   
   
        int parties = 3;
        CyclicBarrier barrier = new CyclicBarrier(parties, () -> System.out.println("All threads reached the barrier."));

        for (int i = 0; i < parties; i++) {
   
   
            new Thread(() -> {
   
   
                try {
   
   
                    System.out.println(Thread.currentThread().getName() + " is waiting on barrier.");
                    barrier.await(); // 等待所有线程到达
                    System.out.println(Thread.currentThread().getName() + " continued.");
                } catch (InterruptedException | BrokenBarrierException e) {
   
   
                    e.printStackTrace();
                }
            }, "Thread-" + (i+1)).start();
        }
    }
}

3. Semaphore - 信号量

介绍

Semaphore 是一种计数信号量,用于控制同时访问特定资源的线程数量,常用于限流和资源池管理。

常见问题与避免策略

  • 问题:未正确释放信号量,导致资源泄露。
  • 避免:确保acquire和release成对出现,即使在异常情况下也要释放。

示例

import java.util.concurrent.Semaphore;

public class SemaphoreDemo {
   
   
    public static void main(String[] args) {
   
   
        Semaphore semaphore = new Semaphore(2); // 允许两个线程同时访问

        for (int i = 0; i < 5; i++) {
   
   
            new Thread(() -> {
   
   
                try {
   
   
                    semaphore.acquire(); // 获取许可
                    System.out.println(Thread.currentThread().getName() + " entered the critical section.");
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + " leaving the critical section.");
                } catch (InterruptedException e) {
   
   
                    Thread.currentThread().interrupt();
                } finally {
   
   
                    semaphore.release(); // 释放许可
                }
            }, "Thread-" + (i+1)).start();
        }
    }
}

总结而言,Phaser, CyclicBarrier, 和 Semaphore 分别提供了不同维度的线程间通信和同步机制。理解它们的特性和正确使用,是实现高效并发程序的关键。在实际应用中,应根据具体场景选择合适的工具,并注意异常处理和资源管理,以避免常见的并发陷阱。

目录
相关文章
|
Java
【源码】【Java并发】【AQS】从ReentrantLock、Semaphore、CutDownLunch、CyclicBarrier看AQS源码
前言 主播觉得,AQS的原理,就是通过这2个队列的协助,实现核心功能,同步队列(CLH队列)和条件队列(Condition队列)。 同步队列(CLH队列) 作用:管理需要获...
359 18
【源码】【Java并发】【AQS】从ReentrantLock、Semaphore、CutDownLunch、CyclicBarrier看AQS源码
|
存储 消息中间件 安全
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
【10月更文挑战第9天】本文介绍了如何利用JUC组件实现Java服务与硬件通过MQTT的同步通信(RRPC)。通过模拟MQTT通信流程,使用`LinkedBlockingQueue`作为消息队列,详细讲解了消息发送、接收及响应的同步处理机制,包括任务超时处理和内存泄漏的预防措施。文中还提供了具体的类设计和方法实现,帮助理解同步通信的内部工作原理。
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
|
Java
JAVA多线程通信:为何wait()与notify()如此重要?
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是实现线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件满足时被唤醒,从而确保数据一致性和同步。相比其他通信方式,如忙等待,这些方法更高效灵活。 示例代码展示了如何在生产者-消费者模型中使用这些方法实现线程间的协调和同步。
289 3
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
367 1
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
469 1
|
Java
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。
在Java多线程编程中,`wait()` 和 `notify()/notifyAll()` 方法是线程间通信的核心机制。它们通过基于锁的方式,使线程在条件不满足时进入休眠状态,并在条件成立时被唤醒,从而有效解决数据一致性和同步问题。本文通过对比其他通信机制,展示了 `wait()` 和 `notify()` 的优势,并通过生产者-消费者模型的示例代码,详细说明了其使用方法和重要性。
289 1
|
Java API 微服务
为什么虚拟线程将改变Java并发编程?
为什么虚拟线程将改变Java并发编程?
614 83
|
Java
如何在Java中进行多线程编程
Java多线程编程常用方式包括:继承Thread类、实现Runnable接口、Callable接口(可返回结果)及使用线程池。推荐线程池以提升性能,避免频繁创建线程。结合同步与通信机制,可有效管理并发任务。
418 6