Java多线程下的其他组件之CyclicBarrier、Callable、Future和FutureTask详解

Java多线程下的其他组件之CyclicBarrier

CyclicBarrier概述

CyclicBarrier是Java中一个同步工具类,用于在多线程中等待所有线程到达某个同步点,然后再一起执行后续操作,这个同步点就是所谓的屏障(barrier),它可重用,即当到达屏障的线程数量达到指定值时,所有线程都可以通过屏障,继续执行下一个操作。

CyclicBarrier同样可以通过计数器(CountDownLatch)实现线程同步的作用,其主要区别在于,CyclicBarrier能够重复使用,而CountDownLatch则无法重复使用。

CyclicBarrier原理

CyclicBarrier的主要原理是利用一个计数器维护需要等待的线程数量,当线程到达屏障时,都会进行计数-1的操作,当计数器为0时,表示所有参与线程都已到达屏障,屏障就会打开,线程继续执行下一个操作。

CyclicBarrier具备以下特点:

  • 可以重复使用
  • 可以在构造时指定一个barrierAction,在屏障打开前最后一个到达的线程执行barrierAction操作
  • 可以在到达屏障时等待一定时间,如果时间到了还没有达到指定线程数,就直接继续执行下一步操作

CyclicBarrier使用示例

下面的例子展示了如何使用CyclicBarrier实现多个线程同时对数组进行求和操作。

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

public class CyclicBarrierDemo {
    private static final int THREAD_COUNT = 5;
    private static final int ARRAY_SIZE = 100;
    private static final int SUM_PER_THREAD = ARRAY_SIZE / THREAD_COUNT;
    private static final int[] ARRAY = new int[ARRAY_SIZE];
    private static int result = 0;

    public static void main(String[] args) {
        //初始化数组
        for (int i = 0; i < ARRAY_SIZE; i++) {
            ARRAY[i] = i + 1;
        }
        //创建CyclicBarrier实例
        CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT, () -> {
            //所有线程到达屏障后,执行求和操作
            System.out.println("结果:" + result);
        });

        //创建多个线程
        for (int i = 0; i < THREAD_COUNT; i++) {
            new Thread(new SumTask(i * SUM_PER_THREAD, (i + 1) * SUM_PER_THREAD, barrier)).start();
        }
    }

    static class SumTask implements Runnable {
        private final int startIndex;
        private final int endIndex;
        private final CyclicBarrier barrier;

        public SumTask(int startIndex, int endIndex, CyclicBarrier barrier) {
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.barrier = barrier;
        }

        @Override
        public void run() {
            int sum = 0;
            //对相应的数组元素进行求和
            for (int i = startIndex; i < endIndex; i++) {
                sum += ARRAY[i];
            }
            System.out.println("线程" + Thread.currentThread().getId() + "求和结果:" + sum);
            result += sum;
            //等待其他线程
            try {
                barrier.await();
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}

在这个例子中,我们将数组分成了5个部分,创建了5个线程,每个线程对应一个区间,每个线程对自己区间内的数组元素进行求和,最后由主线程输出所有线程求和的结果。

Java多线程下的其他组件之Callable和Future

Callable和Future概述

Callable和Future是Java中用于实现带返回值的多线程程序的两个接口,其中Callable代表一个有返回值的任务,而Future则表示异步计算的结果。

Callable和Future的主要特点如下:

  • Callable接口实现了Runnable接口,其call()方法具备返回值
  • Future接口主要提供了以下三个方法:
  • boolean isDone():判断异步计算是否完成
  • V get():获取异步计算的结果,如果计算未完成,该方法会阻塞当前线程,直到计算完成
  • V get(long timeout, TimeUnit unit):在指定的时间内获取异步计算的结果,如果计算未完成,超时就会抛出TimeoutException异常

Callable和Future使用示例

下面的例子展示了如何使用Callable和Future实现多个线程同时求和操作,并输出结果。

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class CallableDemo {
    private static final int THREAD_COUNT = 5;
    private static final int ARRAY_SIZE = 100;
    private static final int SUM_PER_THREAD = ARRAY_SIZE / THREAD_COUNT;
    private static final int[] ARRAY = new int[ARRAY_SIZE];

    public static void main(String[] args) {
        // 初始化数组
        for (int i = 0; i < ARRAY_SIZE; i++) {
            ARRAY[i] = i + 1;
        }
        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT);
        List<Future<Integer>> resultList = new ArrayList<>(THREAD_COUNT);
        // 分配任务,调用submit方法提交任务
        for (int i = 0; i < THREAD_COUNT; i++) {
            int startIndex = i * SUM_PER_THREAD;
            int endIndex = (i + 1) * SUM_PER_THREAD;
            SumTask task = new SumTask(startIndex, endIndex);
            Future<Integer> future = executor.submit(task);
            resultList.add(future);
        }
        // 输出结果
        int result = 0;
        for (Future<Integer> future : resultList) {
            try {
                result += future.get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
        System.out.println("结果:" + result);
        // 关闭线程池
        executor.shutdown();
    }

    static class SumTask implements Callable<Integer> {
        private final int startIndex;
        private final int endIndex;

        public SumTask(int startIndex, int endIndex) {
            this.startIndex = startIndex;
            this.endIndex = endIndex;
        }

        @Override
        public Integer call() {
            int sum = 0;
            // 对相应的数组元素进行求和
            for (int i = startIndex; i < endIndex; i++) {
                sum += ARRAY[i];
            }
            System.out.println("线程" + Thread.currentThread().getId() + "求和结果:" + sum);
            return sum;
        }
    }
}

在这个例子中,我们将数组分成了5个部分,创建了5个Callable任务,每个任务对自己区间内的数组元素进行求和,将结果返回,主线程对所有计算结果求和,得到最终结果输出。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java多线程下的其他组件之CyclicBarrier、Callable、Future和FutureTask详解 - Python技术站

(0)
上一篇 2023年5月18日
下一篇 2023年5月18日

相关文章

  • 微信支付jsapi缺少参数 total_fee 错误分析与解决方法

    下面我就对“微信支付jsapi缺少参数 total_fee 错误分析与解决方法”这个问题进行详细讲解,包括错误原因分析和解决方法。 问题分析 首先,我们需要了解这个错误的含义。这个错误提示是指在调用微信支付 jsapi 时出现了缺少参数 total_fee 的情况。total_fee 参数指订单总金额,如果没有正确传递该参数,那么就会出现这个错误。 下面,我…

    Java 2023年5月23日
    00
  • php URL跳转代码 减少外链

    PHP URL跳转代码用于将一个URL重定向到另一个URL,可以帮助网站管理者减少外链,从而提高网站的安全性,避免了在跨域请求过程中被注入恶意代码的风险。下面将为你详细讲解如何使用PHP URL跳转代码来减少外链。 准备工作 在进行URL跳转之前,你需要知道一些准备工作。首先,需要安装一台web服务器,比如说Apache。其次,需要安装PHP,以便在PHP代…

    Java 2023年6月16日
    00
  • 如何把char数组转换成String

    将char数组转换成String通常可以使用String类的构造函数方法或valueOf()方法。 使用String类的构造函数方法 示例1: char[] charArray = {‘H’, ‘e’, ‘l’, ‘l’, ‘o’}; String str = new String(charArray); System.out.println(str); /…

    Java 2023年5月26日
    00
  • Spring MVC简介_动力节点Java学院整理

    Spring MVC简介 Spring MVC是一种基于Java的轻量级Web框架,用于开发Web应用程序。它基于MVC(模型-视图-控制器)设计模式,该模式将应用程序分为三个主要组成部分,以提供松散耦合的应用程序开发。Spring MVC还提供了中央调度,以便将控制器(Controller)与用户界面(View)分开。 Spring MVC架构 Sprin…

    Java 2023年5月31日
    00
  • SpringBoot中打war包需要注意事项

    SpringBoot中打war包需要注意的事项 SpringBoot默认情况下是以jar包形式运行的,如果需要将SpringBoot项目部署到Web容器中,就需要将项目打成war包。下面是几个需要注意的事项: (1)修改项目的打包方式 在pom.xml文件中,将项目打包方式设置为war,并且去掉spring-boot-starter-web依赖的scope,…

    Java 2023年5月20日
    00
  • Java实现调用外部程序的示例代码

    这里我为你提供一份“Java实现调用外部程序的示例代码”攻略: 1. 确认可供调用的外部程序 在Java代码中调用外部程序之前,首先需要确认可供调用的外部程序是否存在及可用。若存在,则可以直接在Java中通过执行外部程序的命令来进行调用,并获取相应的返回值;若不存在,则需要先进行程序安装或者确认是否已经加入环境变量中。 2. Java代码实现调用外部程序 使…

    Java 2023年5月19日
    00
  • 批量将现有Jar包上传到Maven私服

    批量将现有Jar包上传到Maven私服的过程,大致可以分为以下几个步骤: 准备Maven私服 在私服上创建一个Maven仓库,并提前准备好上传Jar包所需要的账户、密码等信息。 准备Jar包 将需要上传的Jar包,统一归纳至一个目录,在这个目录下,我们可以用以下命令将所有Jar包的文件名打印到一个列表文件中: ls *.jar > list.txt 上…

    Java 2023年5月19日
    00
  • Springboot多数据源配置之整合dynamic-datasource方式

    Springboot多数据源配置之整合dynamic-datasource方式 在实际的应用开发中,我们往往需要连接多个数据库来存储不同的数据,而Springboot提供了多种方式来实现多数据源配置,其中一种方便易用的方式就是使用dynamic-datasource这个开源的库。 本文将介绍如何使用dynamic-datasource来配置Springboo…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部