当前位置: 首页 > news >正文

java八股文面试[多线程]——newWorkStealingPool

newWorkStealingPool是什么?
newWorkStealingPool简单翻译是任务窃取线程池。

newWorkStealingPool 是Java8添加的线程池。和别的4种不同,它用的是ForkJoinPool

使用ForkJoinPool的好处是,把1个任务拆分成多个“小任务”,把这些“小任务”分发到多个线程上执行。这些“小任务”都执行完成后,再将结果合并

之前的线程池中,多个线程共有一个阻塞队列,而newWorkStealingPool 中每一个线程都有一个自己的队列。

当线程发现自己的队列没有任务了,就会到别的线程的队列里获取任务执行。可以简单理解为”窃取“。

一般是自己的本地队列采取LIFO(后进先出)窃取时采用FIFO(先进先出),一个从头开始执行,一个从尾部开始执行,由于偷取的动作十分快速,会大量降低这种冲突,也是一种优化方式。

它有2种实现,如下:
无参
public static ExecutorService newWorkStealingPool() {return new ForkJoinPool(Runtime.getRuntime().availableProcessors(),ForkJoinPool.defaultForkJoinWorkerThreadFactory,null, true);
}

Runtime.getRuntime().availableProcessors()是获取当前系统可以的CPU核心数。

有参

就一个参数parallelism,可以自定义并行度。

public static ExecutorService newWorkStealingPool(int parallelism) {return new ForkJoinPool(parallelism,ForkJoinPool.defaultForkJoinWorkerThreadFactory,null, true);
}
newWorkStealingPool测试案例
public class Thread08_WorkStealing {public static void main(String[] args) {ExecutorService executorService = Executors.newWorkStealingPool(3);for (int i=1; i<= 100; i++){executorService.submit(new MyWorker(i));}while (true){}}
}

运行结果:

ForkJoinPool-1-worker-2正在执行,数值:2
ForkJoinPool-1-worker-1正在执行,数值:1
ForkJoinPool-1-worker-3正在执行,数值:3
ForkJoinPool-1-worker-2正在执行,数值:5
ForkJoinPool-1-worker-1正在执行,数值:4
ForkJoinPool-1-worker-3正在执行,数值:6
ForkJoinPool-1-worker-2正在执行,数值:8
ForkJoinPool-1-worker-3正在执行,数值:9
ForkJoinPool-1-worker-1正在执行,数值:7
。。。。。。

发现确实创建了3个线程来执行任务。

把newWorkStealingPool(3)中参数去掉改成newWorkStealingPool(),结果如下:

ForkJoinPool-1-worker-1正在执行,数值:1
ForkJoinPool-1-worker-3正在执行,数值:3
ForkJoinPool-1-worker-2正在执行,数值:2
ForkJoinPool-1-worker-4正在执行,数值:4
ForkJoinPool-1-worker-5正在执行,数值:5
ForkJoinPool-1-worker-6正在执行,数值:6
ForkJoinPool-1-worker-7正在执行,数值:7
ForkJoinPool-1-worker-0正在执行,数值:8
ForkJoinPool-1-worker-6正在执行,数值:10
ForkJoinPool-1-worker-2正在执行,数值:13
ForkJoinPool-1-worker-0正在执行,数值:15
。。。。。。

发现确实创建了8个线程共同完成任务,因为我CPU有8个核。

ThreadPoolExecutor的核心点

在ThreadPoolExecutor中只有一个阻塞队列存放当前任务

image.png

ForkJoinPool从名字上就能看出一些东西。当有一个特别大的任务时,如果采用上述方式,这个大任务只能会某一个线程去执行。ForkJoin第一个特点是可以将一个大任务拆分成多个小任务,放到当前线程的阻塞队列中。其他的空闲线程就可以去处理有任务的线程的阻塞队列中的任务

image.png

来一个比较大的数组,里面存满值,计算总和

单线程处理一个任务:

/** 非常大的数组 */
static int[] nums = new int[1_000_000_000];
// 填充值
static{for (int i = 0; i < nums.length; i++) {nums[i] = (int) ((Math.random()) * 1000);}
}
public static void main(String[] args) {// ===================单线程累加10亿数据================================System.out.println("单线程计算数组总和!");long start = System.nanoTime();int sum = 0;for (int num : nums) {sum += num;}long end = System.nanoTime();System.out.println("单线程运算结果为:" + sum + ",计算时间为:" + (end  - start));
}

多线程分而治之的方式处理:

/** 非常大的数组 */
static int[] nums = new int[1_000_000_000];
// 填充值
static{for (int i = 0; i < nums.length; i++) {nums[i] = (int) ((Math.random()) * 1000);}
}
public static void main(String[] args) {// ===================单线程累加10亿数据================================System.out.println("单线程计算数组总和!");long start = System.nanoTime();int sum = 0;for (int num : nums) {sum += num;}long end = System.nanoTime();System.out.println("单线程运算结果为:" + sum + ",计算时间为:" + (end  - start));// ===================多线程分而治之累加10亿数据================================// 在使用forkJoinPool时,不推荐使用Runnable和Callable// 可以使用提供的另外两种任务的描述方式// Runnable(没有返回结果) ->   RecursiveAction// Callable(有返回结果)   ->   RecursiveTaskForkJoinPool forkJoinPool = (ForkJoinPool) Executors.newWorkStealingPool();System.out.println("分而治之计算数组总和!");long forkJoinStart = System.nanoTime();ForkJoinTask<Integer> task = forkJoinPool.submit(new SumRecursiveTask(0, nums.length - 1));Integer result = task.join();long forkJoinEnd = System.nanoTime();System.out.println("分而治之运算结果为:" + result + ",计算时间为:" + (forkJoinEnd  - forkJoinStart));
}private static class SumRecursiveTask extends RecursiveTask<Integer>{/** 指定一个线程处理哪个位置的数据 */private int start,end;private final int MAX_STRIDE = 100_000_000;//  200_000_000: 147964900//  100_000_000: 145942100public SumRecursiveTask(int start, int end) {this.start = start;this.end = end;}@Overrideprotected Integer compute() {// 在这个方法中,需要设置好任务拆分的逻辑以及聚合的逻辑int sum = 0;int stride = end - start;if(stride <= MAX_STRIDE){// 可以处理任务for (int i = start; i <= end; i++) {sum += nums[i];}}else{// 将任务拆分,分而治之。int middle = (start + end) / 2;// 声明为2个任务SumRecursiveTask left = new SumRecursiveTask(start, middle);SumRecursiveTask right = new SumRecursiveTask(middle + 1, end);// 分别执行两个任务left.fork();right.fork();// 等待结果,并且获取sumsum = left.join() + right.join();}return sum;}
}

最终可以发现,这种累加的操作中,采用分而治之的方式效率提升了2倍多。

但是也不是所有任务都能拆分提升效率,首先任务得大,耗时要长

知识来源:

Java多线程(十四) Java8 newWorkStealingPool 线程池_瑟王的博客-CSDN博客

相关文章:

java八股文面试[多线程]——newWorkStealingPool

newWorkStealingPool是什么&#xff1f; newWorkStealingPool简单翻译是任务窃取线程池。 newWorkStealingPool 是Java8添加的线程池。和别的4种不同&#xff0c;它用的是ForkJoinPool。 使用ForkJoinPool的好处是&#xff0c;把1个任务拆分成多个“小任务”&#xff0c;把这…...

STM32--RTC实时时钟

文章目录 Unix时间戳时间戳转换BKPRTC简介RTC框图硬件电路RTC的注意事项RTC时钟实验工程 Unix时间戳 Unix 时间戳是从1970年1月1日&#xff08;UTC/GMT的午夜&#xff09;开始所经过的秒数&#xff0c;不考虑闰秒。 时间戳存储在一个秒计数器中&#xff0c;秒计数器为32位/64…...

【N2】例题学习笔记

N2例题 《新"日本语能力测试"例题集》 听力原稿(PDF) 【10】 【問い】この筆者から見た「仕事ができる人」の特徴はどんなことか。 【提问】这位作者认为&#xff0c;仕事能力强的人具有什么特点呢&#xff1f; 【11】 文章 下の文章は、企業のあり方について…...

【数据分享】2006-2021年我国城市级别的道路、桥梁、管线建设相关指标(10多项指标)

《中国城市建设统计年鉴》中细致地统计了我国城市市政公用设施建设与发展情况&#xff0c;在之前的文章中&#xff0c;我们分享过基于2006-2021年《中国城市建设统计年鉴》整理的2006—2021年我国城市级别的市政设施水平相关指标、2006-2021年我国城市级别的各类建设用地面积数…...

视觉SLAM14讲笔记-第7讲-视觉里程计2

直接法的引出 直接法是视觉里程计另一个主要分支&#xff0c;它与特征点法有很大的不同。 使用特征点法估计相机运动时&#xff0c;我们把特征点看作固定在三维空间的不动点。根据它们在相机中的投影位置&#xff0c;通过最小化重投影误差来优化相机运动。 相对地&#xff0c…...

MySQL——单行函数和分组函数

2023.9.3 单行函数的SQL语句学习笔记如下&#xff1a; #常见单行函数介绍&#xff08;部分省略&#xff09; #字符函数 #将姓变大写&#xff0c;名变小写&#xff0c;然后拼接。 SELECT CONCAT(UPPER(last_name), ,LOWER(first_name)) AS 姓名 FROM employees; # 姓名中首字符…...

百度百科词条怎么更新?怎么能顺利更新百科词条?

企业和个人百度百科词条的更新对于他们来说都具有重要的意义&#xff0c;具体如下&#xff1a; 对企业来说&#xff1a; 塑造品牌形象&#xff1a;百度百科是一个常被用户信任并参考的知识平台&#xff0c;通过更新企业词条可以提供准确、全面的企业信息&#xff0c;帮助企业塑…...

PPT怎么转换为PDF格式,收藏这两个在线工具。

PPT是一种常用的演示文稿格式&#xff0c;它可以包含丰富的动画效果和超链接&#xff0c;让你的内容更加生动和有趣。但是&#xff0c;如果你想将PPT分享给别人&#xff0c;或者在不同的设备上查看&#xff0c;你可能会遇到一些问题&#xff0c;比如&#xff1a; PPT文件太大&a…...

八大排序算法----堆排序

堆排序的基本步骤&#xff1a;&#xff08;以从大到小的顺序排序为例&#xff09; 1.构建大顶堆&#xff08;每个结点的值都大于或等于其左右孩子结点的值&#xff09; 2.排序&#xff1a;每次堆顶的元素取出来&#xff08;整个堆中值最大&#xff09;&#xff0c;与最后一个…...

Docker Desktop 设置镜像环境变量

点击run 展开Optional settings container name &#xff1a;容器名称 Ports&#xff1a;根据你需要的端口进行输入&#xff0c;不输入则默认 后面这个 比如我这个 5432 Volumes&#xff1a;卷&#xff0c;也就是做持久化 需要docker 数据保存的地方 Environment variables…...

springboot之一:配置文件(内外部配置优先顺序+properties、xml、yaml基础语法+profile动态切换配置、激活方式)

配置的概念&#xff1a; Spring Boot是基于约定的&#xff0c;所以很多配置都有默认值&#xff0c;但如果想使用自己的配置替换默认配置的话&#xff0c;就可以使用application.properties或者application.yml(application.yaml)进行配置。 注意配置文件的命名必须是applicat…...

涛然自得周刊(第 5 期):蝲蛄吟唱的地方

作者&#xff1a;何一涛 日期&#xff1a;2023 年 8 月 20 日 涛然自得周刊主要精选作者阅读过的书影音内容&#xff0c;不定期发。历史周刊内容可以看这里。 电影 《沼泽深处的女孩》 改编自小说《蝲蛄吟唱的地方》&#xff0c;主角是一位在沼泽地独自生活并长大的女孩&…...

Android Ble蓝牙App(七)扫描过滤

Ble蓝牙App&#xff08;七&#xff09;扫描过滤 前言目录正文一、增加菜单二、使用MMKV① 添加依赖② 封装MMKV③ 使用MMKV 三、过滤空设备名四、过滤Mac地址五、过滤RSSI六、源码 前言 在上一篇文章中了解了MTU的相关知识以及对于设备操作信息的展示&#xff0c;本篇文章中将增…...

小程序当前页面栈以及跳转

1.调用页面栈刷新接口 let pages getCurrentPages(); //当前页面栈 if (pages.length > 1) { let beforePage pages[pages.length - 2]; //获取上一个页面实例对象 beforePage.$vm.getActivityLi…...

jQuery获取表单的值val()

&#xff08;1&#xff09;页面中有很多元素&#xff0c;包括表单中的输入项&#xff0c;如输入文本框等&#xff1b;获取、设置、输入文本框的值&#xff1b;val()方法。 &#xff08;2&#xff09;也包括<p>、<span>等元素&#xff1b;获取、设置这些元素的文本…...

【专栏必读】数字图像处理(MATLAB+Python)专栏目录导航及学习说明

文章目录 第一章&#xff1a;绪论第二章&#xff1a;数字图像处理基础第三章&#xff1a;图像基本运算第四章&#xff1a;图像的正交变换第五章&#xff1a;图像增强第六章&#xff1a;图像平滑第七章&#xff1a;图像锐化第八章&#xff1a;图像复原第九章&#xff1a;图像形态…...

2023年非证券类投资银行业发展报告

第一章 行业概况 非证券投资银行业是一个专门为公司、政府和高净值个人提供金融服务的行业&#xff0c;与传统的证券投资银行不同&#xff0c;其主要业务不涉及证券交易&#xff0c;而是注重为客户提供咨询服务、融资和投资管理等服务。 非证券投资银行通常涉及的业务领域包括…...

Matlab 如何把频谱图的纵坐标设置为分贝刻度

Matlab 如何把频谱图的纵坐标设置为分贝刻度 Matlab代码如下&#xff1a; % 如何把频谱图的纵坐标设置为分贝刻度 % % pr2_2_6 clc; clear; close all;load pr2_2_6_sndata1.mat % 读入数据 X fft(y); % FFT n2 1:L/21; % 计算正频率…...

VUE写后台管理(2)

VUE写后台管理&#xff08;2&#xff09; 1.环境2.Element界面3.Vue-Router路由后台1.左导航栏2.上面导航条 1.环境 1.下载管理node版本的工具nvm&#xff08;Node Version Manager&#xff09; 2.安装node(vue工程的环境管理工具)&#xff1a;nvm install 16.13.0 3.安装vue工…...

RHCSA8.2

Node1 配置您的系统以使用默认存储库 配置您 的系统以使用默认存储库YUM 存储库已可以从 http://foundation0.ilt.example.com/dvd/BaseOS 和 http://foundation0.ilt.example.com/dvd/AppStream 使用配置您的系统&#xff0c;以将这些位置用作默认存储库[rootclear ~]# cat …...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing

Muffin 论文 现有方法 CRADLE 和 LEMON&#xff0c;依赖模型推理阶段输出进行差分测试&#xff0c;但在训练阶段是不可行的&#xff0c;因为训练阶段直到最后才有固定输出&#xff0c;中间过程是不断变化的。API 库覆盖低&#xff0c;因为各个 API 都是在各种具体场景下使用。…...

【Veristand】Veristand环境安装教程-Linux RT / Windows

首先声明&#xff0c;此教程是针对Simulink编译模型并导入Veristand中编写的&#xff0c;同时需要注意的是老用户编译可能用的是Veristand Model Framework&#xff0c;那个是历史版本&#xff0c;且NI不会再维护&#xff0c;新版本编译支持为VeriStand Model Generation Suppo…...

GraphQL 实战篇:Apollo Client 配置与缓存

GraphQL 实战篇&#xff1a;Apollo Client 配置与缓存 上一篇&#xff1a;GraphQL 入门篇&#xff1a;基础查询语法 依旧和上一篇的笔记一样&#xff0c;主实操&#xff0c;没啥过多的细节讲解&#xff0c;代码具体在&#xff1a; https://github.com/GoldenaArcher/graphql…...