首页 > 编程语言 >5.5. Java并发工具类(如CountDownLatch、CyclicBarrier等)

5.5. Java并发工具类(如CountDownLatch、CyclicBarrier等)

时间:2023-05-31 23:36:34浏览次数:45  
标签:Java 5.5 示例 System 线程 CountDownLatch println CyclicBarrier out

5.5.1 CountDownLatch

CountDownLatch是一个同步辅助类,它允许一个或多个线程等待,直到其他线程完成一组操作。CountDownLatch有一个计数器,当计数器减为0时,等待的线程将被唤醒。计数器只能减少,不能增加。

示例:使用CountDownLatch等待所有线程完成任务

假设我们有一个任务需要三个子任务完成,我们可以使用CountDownLatch来等待所有子任务完成。

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(3);

        for (int i = 1; i <= 3; i++) {
            final int taskNumber = i;
            new Thread(() -> {
                System.out.println("Task " + taskNumber + " started");
                try {
                    Thread.sleep(1000 * taskNumber);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + taskNumber + " completed");
                latch.countDown();
            }).start();
        }

        System.out.println("Waiting for all tasks to complete...");
        latch.await();
        System.out.println("All tasks completed");
    }
}

在这个示例中,我们创建了一个CountDownLatch并设置初始计数器为3。每个子任务完成后,调用latch.countDown()减少计数器。主线程调用latch.await()等待所有子任务完成。

5.5.2 CyclicBarrier

CyclicBarrier是一个同步辅助类,它允许一组线程相互等待,直到所有线程都准备好继续执行。当所有线程都到达屏障点时,屏障将打开。CyclicBarrier可以重复使用。

示例:使用CyclicBarrier同步多个线程

假设我们有三个线程需要在某个点同步,我们可以使用CyclicBarrier实现这个目的。

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

public class CyclicBarrierExample {
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(3, () -> System.out.println("All threads are ready to proceed"));

        for (int i = 1; i <= 3; i++) {
            final int taskNumber = i;
            new Thread(() -> {
                System.out.println("Task " + taskNumber + " is ready");
                try {
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println("Task " + taskNumber + " is proceeding");
            }).start();
        }
    }
}

在这个示例中,我们创建了一个CyclicBarrier并设置参与者数量为3。每个线程在准备好继续执行之前调用barrier.await()。当所有线程都准备好时,屏障将打开,所有线程将继续执行。

5.5.3 Semaphore

Semaphore是一个计数信号量,它维护了一个许可集。线程可以请求许可,如果有可用的许可,线程将获得许可并继续执行。否则,线程将阻塞,直到有可用的许可。许可可以由任何线程释放。Semaphore可用于实现资源池、限制并发访问等。

示例:使用Semaphore限制并发访问

假设我们有一个只能同时处理三个请求的服务器,我们可以使用Semaphore来实现并发访问限制。

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(3);

        for (int i = 1; i <= 10; i++)            final int clientNumber = i;
            new Thread(() -> {
                try {
                    System.out.println("Client " + clientNumber + " is trying to connect");
                    semaphore.acquire();
                    System.out.println("Client " + clientNumber + " is connected");
                    Thread.sleep(2000);
                    System.out.println("Client " + clientNumber + " is disconnected");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release();
                }
            }).start();
        }
    }
}

在这个示例中,我们创建了一个Semaphore并设置初始许可数量为3。每个客户端线程在连接服务器之前调用semaphore.acquire()请求许可。当许可可用时,线程将获得许可并继续执行。线程完成后,调用semaphore.release()释放许可。

5.5.4 Exchanger

Exchanger是一个同步辅助类,它允许两个线程在一个临界点交换数据。当两个线程都到达交换点时,它们将交换数据。Exchanger可以用于遗传算法、管道设计等。

示例:使用Exchanger交换数据

假设我们有两个线程,一个生成数据,另一个处理数据。我们可以使用Exchanger在这两个线程之间交换数据。

import java.util.concurrent.Exchanger;

public class ExchangerExample {
    public static void main(String[] args) {
        Exchanger<String> exchanger = new Exchanger<>();

        new Thread(() -> {
            try {
                String data = "Data from producer";
                System.out.println("Producer is sending: " + data);
                String receivedData = exchanger.exchange(data);
                System.out.println("Producer received: " + receivedData);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            try {
                String data = "Data from consumer";
                System.out.println("Consumer is sending: " + data);
                String receivedData = exchanger.exchange(data);
                System.out.println("Consumer received: " + receivedData);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

在这个示例中,我们创建了一个Exchanger。生产者和消费者线程在交换数据前调用exchanger.exchange(data)。当两个线程都到达交换点时,它们将交换数据。

5.5.5 Phaser

Phaser是一个灵活的同步辅助类,它允许一组线程相互等待,直到所有线程都准备好继续执行。与CyclicBarrier类似,但Phaser更加灵活,可以动态调整参与者数量和支持多个阶段。

示例:使用Phaser同步多个线程

假设我们有三个线程需要在某个点同步,我们可以使用Phaser实现这个目的。

import java.util.concurrent.Phaser;

public class PhaserExample {
    public static void main(String[] args) {
        Phaser phaser = new Phaser(3);

        for (int i = 1; i <= 3; i++) {
            final int taskNumber = i;
            new Thread(() -> {
                System.out.println("Task " + taskNumber + " is ready");
                phaser.arriveAndAwaitAdvance();
                System.out.println("Task " + taskNumber + " is proceeding");
            }).start();
        }
    }
}

在这个示例中,我们创建了一个Phaser并设置参与者数量为3。每个线程在准备好继续执行之前调用phaser.arriveAndAwaitAdvance()。当所有线程都准备好时,屏障将打开,所有线程将继续执行。

这些并发工具类为Java多线程编程提供了强大的支持,帮助我们更轻松地实现各种同步和并发场景。希望这些示例能帮助你理解并掌握这些工具类的用法。
推荐阅读:

https://mp.weixin.qq.com/s/dV2JzXfgjDdCmWRmE0glDA

https://mp.weixin.qq.com/s/an83QZOWXHqll3SGPYTL5g

file

标签:Java,5.5,示例,System,线程,CountDownLatch,println,CyclicBarrier,out
From: https://www.cnblogs.com/yaoqian/p/17447650.html

相关文章

  • Java内存管理
    Java的内存管理有内存分配与内存回收,Java中内存分配与回收完全用虚拟机自动实现。 内存分为:栈,堆,代码区,静态变量存储区。 栈:存放局部变量,引用对象,形参(形参是一种特殊的局部变量)。例如,定义局部变量inti=20;那么i分配在栈中,栈中的内容用完后立即释放,所以速度较快,注意一点,基本数......
  • java List分批处理
    1packagecom.example.demo;2importcom.google.common.collect.Lists;3importjava.util.ArrayList;4importjava.util.List;5publicclassTest{6publicstaticvoidmain(String[]args){7List<Integer>list=newArrayList<......
  • pollard_rho大数分解Java版
    代码:importjava.math.BigInteger;importjava.security.SecureRandom;classPollardRho{privatefinalstaticBigIntegerZERO=newBigInteger("0");privatefinalstaticBigIntegerONE=newBigInteger("1");privatefina......
  • 3、实战案例:部署基于JAVA的博客系统JPress
    官方网站:http://www.jpress.io/安装包下载第一步:[root@ubuntu2004]#mkdir/data/jpress/-p创建网站数据存放的目录,ROOT可以不建把下载好的包拉进/data/jpress/目录,并改名为ROOT.war,它会自动解压成一个ROOT文件夹[root@ubuntu2004jpress]#rz-Erzwaitingtoreceive.[root@......
  • [SprigMVC/SpringBoot] JSON序列化专题之日期序列化问题:接口报Jackson框架错误“Inva
    0序言今日工作中遇到的一个bug。各位看官且听我娓娓道来。1问题描述请求接口时,service层返回到controller层的数据结构为List<Map<Strig,Object>>,而Map中存在一个key=date,valuetype=java.time.LocalDate的Entry,且日志报如下错误:InvalidDefinitionException:Java8date......
  • Java中序列化和反序列化解释
    在Java中,序列化(Serialization)是指将对象的状态转换为字节流的过程,以便将其保存到文件、在网络中传输或持久化到数据库中。而反序列化(Deserialization)则是将字节流转换回对象的过程,恢复对象的状态。序列化和反序列化主要用于以下场景:1.对象持久化:通过序列化,可以将对象的状态保存......
  • 学习JavaSE基础-day1
    JRE和JDKJRE:Java运行环境,如果想要运行Java程序至少要安装JREJDK:Java开发环境(开发工具包),如果要开发Java程序,必须安装JDKJRE=JVM+核心类库JDK=JRE+开发工具包JDK>JRE>JVM关系如图所示: JDK下载地址:www.oracle.com配置Path环境变量:希望可以在命令窗口的任意的......
  • Java开发必备软件合集
    IDEA安装详情,包含激活教程,和相关配置教程。IDEA安装配置步骤详解 IntelliJIDEA中有什么让你相见恨晚的技巧IDEA快捷键大全 Navicat安装教程,激活教程navicat介绍(包含安装指导) IDEAvsEclipse:使用体验对比IDEA对比 【待更新】......
  • 【Java】线程池配置
     先看JUC包自带的一个资源线程池执行器:初始化参数如下ThreadPoolExecutorthreadPoolExecutor=newThreadPoolExecutor(corePoolSize,//核心线程数量maximumPoolSize,//峰值线程数量keepAliveTime,//保留时限,当线程数量超出峰值数量时,保......
  • 【随手记录】关于Java字符串长度
    在java当中,在运行期间,字符串的长度是有最大限制的:21亿,也就是4GB;在编译期间,字符串的长度最大为:65534。字符串的内容是由一个字符数组char[]来存储的,由于数组的长度及索引是整数,Integer的最大范围是2^31-1,所以数组的最大长度可以使【0~2^31-1】通过计算是大概4GB=(2*2^31-......