Java——使用多线程从list中不重复地取出数据并进行处理,给多线程任务添加单项任务计时和总耗时

news2024/10/9 14:23:27

Java——使用多线程从list中不重复地取出数据并进行处理,给多线程任务添加单项任务计时和总耗时

  • 一、最简版-无参数传递
    • 1.创建业务类,实现Runnable接口
    • 2.创建线程,实例化自己创建的业务类并调用
    • 3.运行结果
  • 二、加强版-有参数传递
    • 1.创建业务类,实现Runnable接口
    • 2.创建线程,实例化自己创建的业务类并调用
    • 3.运行结果
  • 三、加加强版-有参数传递且带单项任务计时和总耗时
    • 1.创建业务类,实现Runnable接口
    • 2.创建线程,实例化自己创建的业务类并调用
    • 3.运行结果

一、最简版-无参数传递

1.创建业务类,实现Runnable接口

把处理数据的方法写在处理类中重写的Runnable接口的run()方法中。

import lombok.extern.slf4j.Slf4j;


import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class Demo01Runnable implements Runnable {

    //实现父接口Runnable中的run方法
    @Override
    public void run() {
        //调用自己的业务方法
        doSomething();
    }

    //自己业务的方法
    private void doSomething() {
        log.info("随便干点啥...");
    }
}

2.创建线程,实例化自己创建的业务类并调用

@Slf4j
@Service
public class FileOperateService {

    // 业务处理的线程池(设置为4个线程)
    private static ExecutorService pool = Executors.newFixedThreadPool(4);

    //在这里调用
	public static void main(String[] args) {
        //创建一个Runnable对象,并将CountDownLatch的实例对象传入
        Demo01Runnable runnable = new Demo01Runnable();
        for (int i = 0; i < 4; i++) {
            //从线程池取出一个线程来执行业务,遍历4次就是取出4个
            pool.execute(runnable);
        }
    }
}

3.运行结果

如图所示可以看到创建了4个线程
在这里插入图片描述

二、加强版-有参数传递

大部分的业务都不是独立运行的,会有参数传递到业务中,如果需要多线程调用的业务有主线程的参数需要传递过去,就可以把参数写在实现了Runnable接口的业务类的私有属性中,用业务类的构造方法传参。具体代码改造如下:

1.创建业务类,实现Runnable接口

  • 添加了私有属性Integer num

  • 添加了num的构造方法

  • 在方法中调用了属性num

import lombok.extern.slf4j.Slf4j;


import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class Demo02Runnable implements Runnable {
    private Integer num;

    public Demo02Runnable(Integer num){
        this.num = num;
    }

    //实现父接口Runnable中的run方法
    @Override
    public void run() {
        //调用自己的业务方法
        doSomething();
    }

    //自己业务的方法
    private void doSomething() {
        log.info("第 {} 个线程开始干活", num);
    }
}

2.创建线程,实例化自己创建的业务类并调用

  • new Demo02Runnable对象时候将num作为参数传递构造方法中
@Slf4j
@Service
public class FileOperateService {

    // 业务处理的线程池(设置为4个线程)
    private static ExecutorService pool = Executors.newFixedThreadPool(4);

    //在这里调用
	public static void main(String[] args) {

        for (int i = 0; i < 4; i++) {
            //创建一个Runnable对象,并将CountDownLatch的实例对象传入
            Demo02Runnable runnable = new Demo02Runnable(i);
            //从线程池取出一个线程来执行业务,遍历4次就是取出4个
            pool.execute(runnable);
        }
    }
}

3.运行结果

如图所示可以看到参数成功传递进去了

在这里插入图片描述

三、加加强版-有参数传递且带单项任务计时和总耗时

在业务里,使用多个线程并行处理业务能够极大的加快处理速度,但是如果我们需要明确掌握每次处理业务的耗时,和所有业务处理完成的总耗时,就可以通过CountDownLatch来帮我们实现。

1.创建业务类,实现Runnable接口

  • 添加了私有属性:

    • Integer size -用来记录任务的总数量
    • long ct -用来记录任务开始的时间
    • AtomicInteger taskProgress -用来记录任务执行的数量
    • CountDownLatch latch -用来统计单项任务计时和总耗时
  • 添加了以上属性的构造方法

  • 在方法中调用了以上属性

import lombok.extern.slf4j.Slf4j;


import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class Demo03Runnable implements Runnable {
    private Integer size;
    private long ct;
    private AtomicInteger taskProgress;
    private CountDownLatch latch;
    
    public Demo03Runnable(Integer size, long ct, AtomicInteger taskProgress, CountDownLatch latch){
        this.size = size;
        this.ct = ct;
        this.taskProgress = taskProgress;
        this.latch = latch;
    }

    //实现父接口Runnable中的run方法
    @Override
    public void run() {
        //调用自己的业务方法
        doSomething();
    }

    //自己业务的方法
    private void doSomething() {
        //从系统获取业务开始执行时的时间
        long curr = System.currentTimeMillis();
        try {
            //线程睡0.5秒来代替任意业务逻辑
            Thread.sleep(500);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            //让CountDownLatch计数器减1
            latch.countDown();
            //统计任务数量,即本条业务被线程执行的次数(每执行一次就+1
            int task = taskProgress.getAndIncrement();
            log.info("任务进度 {} / {} = {}%\t {} 号任务耗时:{} - 任务总耗时:{} ", task, size, String.format("%.2f", task * 100.0 / size), task, System.currentTimeMillis() - curr, System.currentTimeMillis() - ct);

        }
    }
}

2.创建线程,实例化自己创建的业务类并调用

  • 任务开始前,创建CountDownLatch对象用于在指定位置控制所有子线程完成后再走主线程指定代码
  • 任务开始前,从系统获取当前时间作为任务开始时间
  • 任务开始前,创建AtomicInteger用于统计任务执行数量
  • 创建Demo03Runnable对象时候将size(任务总数量),ct(任务开始时间),taskProgress(任务执行数量),latch作为参数传递构造方法中
  • 主线程中调用子线程的方法结束后,调用await()方法,阻塞主线程,在这之后的代码只会在子线程全部执行完成之后,才开始执行。因此在这里再次获取系统当前时间,用于和前面记录的时间计算后统计相关耗时。
@Slf4j
@Service
public class FileOperateService {

    // 业务处理的线程池(设置为4个线程)
    private static ExecutorService pool = Executors.newFixedThreadPool(4);

    //在这里调用
	public static void main(String[] args) {

        //创建一个CountDownLatch对象,并调用构造器将计数器设置为总任务数量
        CountDownLatch latch = new CountDownLatch(10);
        //记录任务开始时间
        long ct = System.currentTimeMillis();
        //记录任务开始数量
        final AtomicInteger taskProgress = new AtomicInteger(1);
        for (int i = 1; i <= 10; i++) {
            //创建一个Runnable对象,并将CountDownLatch的实例对象传入
            Demo03Runnable runnable = new Demo03Runnable(10,ct,taskProgress,latch);
            pool.execute(runnable);
        }
        //调用await()方法,阻塞主线程,当上述启动的所有分线程都执行完后,主线程才会被放行
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //记录下结束时间
        log.info("任务全部执行完成,总耗时:{} 毫秒", System.currentTimeMillis() - ct);
    }
}

3.运行结果

如图所示

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/135704.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第8季1:海思平台OSD的理论基础

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、OSD概述 1、区域管理模块 “OSD”是“on screen display”的缩写&#xff0c;即在屏幕上播放。 用户需要在视频中叠加OSD或者色块&#xff0c;来显示一些特定信息&#xff0c;比如通道号、时…

浅谈Java并发

Java并发是比较难的知识点&#xff0c;难于对并发的理解。并发要从操作系统和硬件层面去理解&#xff0c;才会比较深入&#xff0c;而不单单是从编程语言的逻辑去理解。 首先对于并发要清楚的几点&#xff1a; 线程可能在任何时刻被切换。 计算机只对硬件指令保证原子性。 CP…

关于一名资深Java程序员在移动端的进阶之路

目录 那年刚毕业 初识移动端 H5开始入门 微信小程序开发 未来的目标(唯有热爱&#xff0c;可抵这岁月漫长) 既然进来了&#xff0c;就帮我点亮五星好评吧&#xff0c;你的五星就是对我最大的支持和鼓励…… https://bbs.csdn.net/topics/611387335 今天呢&#xff0c;就借…

Prometheus配合 alertmanager 使用企业微信告警(坑已平!!!)

部署Prometheus 和 Alertmanager略 安装包部署prometheusGrafananode_exporter_争取不加班&#xff01;的博客-CSDN博客 prometheus监控报警部署Alertmanager_争取不加班&#xff01;的博客-CSDN博客 配置企业微信报警 首先使用企业微信创建一个企业 然后点击头像&#xff…

C++进阶 map和set

作者&#xff1a;小萌新 专栏&#xff1a;C进阶 作者简介&#xff1a;大二学生 希望能和大家一起进步&#xff01; 本篇博客简介&#xff1a;简单介绍C中map和set容器 map和set关联式容器树形结构与哈希结构键值对setset的介绍set的定义方式方式一&#xff1a; 构造一个某类型的…

声纹图-声谱图-js之wavesurfer.js(配置、事件、方法中文版翻译)

配置信息 optiontypedefaultEnglish descriptiontranslateaudioRatefloat1Speed at which to play audio. Lower number is slower.播放音频的速度。数值越低&#xff0c;速度越慢。audioContextobjectnoneUse your own previously initialized AudioContext or leave blank.n…

挺进2023 年的JavaScript 框架

瞥见未来的美妙之处在于&#xff0c;道路永远不会完全清晰。我们可以观察趋势&#xff0c;观察创新并尝试规划路线。更好的是&#xff0c;我们可以成为这些创新的一部分来指导方向。但没有什么是确定的。 2022 年发布了大量推动 Web 开发的重大版本。我们看到了 Astro 和 Svel…

Jetson NX + yolov5 v5.0 + TensorRT加速+调用usb摄像头

上一篇笔记记录了如何使用yolov5使用usb摄像头使用权重进行测试,测试效果如下 本篇文章具体操作步骤如下就可以了&#xff0c;切记版本要对应 &#xff0c;我产生这个错误的原因就是版本问题&#xff0c;成功转换但是还是卡顿&#xff0c;估计是硬件usb问题&#xff0c;加速以后…

2023年最值得学习的10大编程语言

作为一名程序员&#xff0c;我们的目标之一就是学习新技术和编程语言&#xff0c;但是你应该学习哪些语言呢&#xff1f;由于学习一门编程语言既需要时间又需要耐心&#xff0c;因此您应该学习一门值得付出努力的语言&#xff1b;我的意思是&#xff0c;它可以帮助你获得更好的…

2023前端必会手写面试题整理

实现一个compose函数 组合多个函数&#xff0c;从右到左&#xff0c;比如&#xff1a;compose(f, g, h) 最终得到这个结果 (...args) > f(g(h(...args))). 题目描述:实现一个 compose 函数 // 用法如下: function fn1(x) {return x 1; } function fn2(x) {return x 2; } …

UTF-8编码

阅读该文章之前&#xff0c;请阅读以下两篇文章&#xff0c;了解GBK编码和Unicode编码&#xff1a; GBK编码的理解_sgmcy的博客-CSDN博客 Unicode编码的理解_sgmcy的博客-CSDN博客 UTF的意思是&#xff1a;Unicode Transformation Format 。也就是Unicode 转换格式。可见&am…

python初级教程七 JSON 数据解析

JSON 数据解析 JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式。 Python3 中可以使用 json 模块来对 JSON 数据进行编解码&#xff0c;它包含了两个函数&#xff1a; json.dumps(): 对数据进行编码。 json.loads(): 对数据进行解码。 在 json 的编解码过程…

【数据结构】C语言实现双链表

目录 前言 双链表节点定义 接口函数实现 初始化函数 创建节点 打印双链表 尾插节点 尾删节点 头插节点 头删节点 指定位置前插入 删除指定位置节点 改写插入删除 判断链表是否为空 计算链表长度 销毁链表 双链表完整代码 浅谈链表及顺序表 前言 前面我们已经实…

Speed and Memory Efficient Dense RGB-D SLAM in Dynamic Scenes论文笔记

Speed and Memory Efficient Dense RGB-D SLAM in Dynamic Scenes论文笔记 论文中的主要引用文献&#xff1a; [7:A coarse and relevant 3d representation for fast and lightweight rgb-d mapping] 超表元建图 [14: Fast optical flow using dense inverse search] 稠密光流…

后端Web开发框架(Java)

为什么使用Spring Boot 简化配置&#xff0c;无需编写太多的 xml 配置文件&#xff0c;效率很高&#xff1b;Spring 可以整合很多各式各样的框架&#xff0c;并能很好的集成&#xff1b;基于 Spring 构建&#xff0c;使开发者快速入门&#xff0c;门槛很低&#xff1b;Spring …

LabVIEW调用自己写的DLL

首先&#xff0c;我用的LabVIEW是8.5版本的&#xff0c;比较老但工作需要 先新建VI 程序框图中选择 互连接口 - 库与可执行程序 选择 调用库函数… 拖到面板 并右击它 选择配置 在库名或路径中选择写好的DLL方案中的DEBUG中dll文件 确定以后就要选择哪个函数&#xff0c;并…

【数字图像处理】毛笔字细化

源码链接&#xff1a;calligraphy.cpp 一、实验要求 附件是书法毛笔字&#xff0c;请将附件图片中“年少有为”四个字进行笔画细化。 二、实验内容 首先观察图片&#xff0c;是只将黑色的毛笔字部分进行细化&#xff0c;所以需要先把印章这类的区域去除。先通过将图片转到h…

Content Security Policy (CSP) 介绍

内容安全策略 (CSP) 是一个额外的安全层&#xff0c;用于检测并削弱某些特定类型的攻击&#xff0c;包括跨站脚本 (XSS) 和数据注入攻击等。无论是数据盗取、网站内容污染还是散发恶意软件&#xff0c;这些攻击都是主要的手段。 起因 当我不经意间在 Twitter 页面 view source…

JavaScript 简单类型与复杂类型

JavaScript 简单类型与复杂类型 目录JavaScript 简单类型与复杂类型1. 简单类型与复杂类型2. 堆和栈3. 简单类型的内存分配4.复杂类型的内存分配5. 简单类型传参6. 复杂类型传参7.下面是代码1、Math对象最大值2. 封装自己的数学对象3. Math绝对值和三个取整方法4.Math对象获取随…

WebSocket实现聊天室

需求 实现用户登录功能展示用户好友列表功能实现用户历史消息展示实现单聊信息和群聊信息 效果展示 用户登录 好友列表展示 历史消息展示 聊天 代码实现 说明&#xff1a;Springboot项目&#xff0c;页面是用 thymeleaf 整合的。 maven依赖 <dependencies><depen…