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日

相关文章

  • vue 请求后台数据的实例代码

    Vue.js 是一款 MVVM 框架,常用来构建单页应用程序(SPA)。在前后端分离的架构下,前端需要向后台发送请求来获取数据。Vue 框架可以通过内置的 axios 库来发送请求和接收响应。下面我们将以一个示例代码的形式演示如何使用 Vue.js 发送请求并处理响应。 步骤一:安装 axios 在使用 axios 前,需要先通过npm或yarn 安装 ax…

    Java 2023年6月15日
    00
  • java学生信息管理系统MVC架构详解

    Java学生信息管理系统MVC架构详解 什么是MVC? MVC指的是Model-View-Controller,是一种软件设计模式,用于将一个应用程序分为三个关键组件:“Model”(模型), “View”(视图)和“Controller”(控制器)。这种模式的目的是分离应用程序的关注点以提高应用程序的可维护性和扩展性。 具体而言,“Model”(模型)处理…

    Java 2023年5月23日
    00
  • Java简易抽奖系统小项目

    Java简易抽奖系统小项目攻略 系统需求 本系统需要Java环境和命令行界面,可以在Windows、Linux和macOS等平台上运行。 实现步骤 第一步:初始化 本系统需要一个抽奖池,因此我们可以创建一个ArrayList来保存所有的奖品信息。同时,我们需要引入java.util.Random类生成随机数。 import java.util.ArrayLi…

    Java 2023年5月30日
    00
  • 什么是Java调试技术?

    什么是Java调试技术 Java调试技术是在开发过程中定位和解决问题的必备能力之一。它通过一系列调试工具、调试器和技巧,帮助我们快速定位代码问题并进行修复。 Java调试技术的使用攻略 步骤1:启用调试模式 在开发Java应用程序时,应该启用调试模式,这样可以让我们在程序中设置断点,并允许调试器来监视变量和执行。 在启用调试模式时,需要在运行Java应用程序…

    Java 2023年5月11日
    00
  • java二维数组指定不同长度实例方法

    实现Java二维数组指定不同长度的方法有很多种,下面我将罗列一些常用的方法,并提供两条示例说明。 方法一:定义不规则数组 不规则数组是指定义一个数组,其中包含若干行,每行的元素个数不同。例如: int[][] arr = new int[3][]; arr[0] = new int[]{1, 2}; arr[1] = new int[]{3, 4, 5}; …

    Java 2023年5月26日
    00
  • SpringBoot中如何启动Tomcat流程

    SpringBoot是现在Java开发中比较热门的框架之一,它以快速启动、无代码生产和简洁的配置等优势著称。Tomcat是其中最常见的Web容器之一,本文将详细讲解在SpringBoot中如何启动Tomcat的流程。 1. SpringBoot启动Tomcat的流程 SpringBoot启动Tomcat的流程步骤如下: SpringBoot启动器根据项目中引…

    Java 2023年6月2日
    00
  • Spring Boot中使用Spring-data-jpa的配置方法详解

    “Spring Boot中使用Spring-data-jpa的配置方法详解”的攻略如下: 1. 添加Spring Data JPA依赖 在项目的pom.xml文件中添加Spring Data JPA的依赖: <dependency> <groupId>org.springframework.boot</groupId> &…

    Java 2023年5月20日
    00
  • java如何实现判断文件的真实类型

    Java如何实现判断文件真实类型的攻略如下: 1.使用后缀名判断文件类型 Java可以通过文件后缀名来判断文件类型。例如,如果文件名以”.txt”结尾,则是文本文件。这种方法适用于大多数文件类型,但不适用于所有文件。以下是示例代码: import java.io.File; public class FileTypeChecker { public stat…

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