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中只有一个阻塞队列存放当前任务

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

来一个比较大的数组,里面存满值,计算总和
单线程处理一个任务:
/** 非常大的数组 */
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是什么? newWorkStealingPool简单翻译是任务窃取线程池。 newWorkStealingPool 是Java8添加的线程池。和别的4种不同,它用的是ForkJoinPool。 使用ForkJoinPool的好处是,把1个任务拆分成多个“小任务”,把这…...
STM32--RTC实时时钟
文章目录 Unix时间戳时间戳转换BKPRTC简介RTC框图硬件电路RTC的注意事项RTC时钟实验工程 Unix时间戳 Unix 时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。 时间戳存储在一个秒计数器中,秒计数器为32位/64…...
【N2】例题学习笔记
N2例题 《新"日本语能力测试"例题集》 听力原稿(PDF) 【10】 【問い】この筆者から見た「仕事ができる人」の特徴はどんなことか。 【提问】这位作者认为,仕事能力强的人具有什么特点呢? 【11】 文章 下の文章は、企業のあり方について…...
【数据分享】2006-2021年我国城市级别的道路、桥梁、管线建设相关指标(10多项指标)
《中国城市建设统计年鉴》中细致地统计了我国城市市政公用设施建设与发展情况,在之前的文章中,我们分享过基于2006-2021年《中国城市建设统计年鉴》整理的2006—2021年我国城市级别的市政设施水平相关指标、2006-2021年我国城市级别的各类建设用地面积数…...
视觉SLAM14讲笔记-第7讲-视觉里程计2
直接法的引出 直接法是视觉里程计另一个主要分支,它与特征点法有很大的不同。 使用特征点法估计相机运动时,我们把特征点看作固定在三维空间的不动点。根据它们在相机中的投影位置,通过最小化重投影误差来优化相机运动。 相对地,…...
MySQL——单行函数和分组函数
2023.9.3 单行函数的SQL语句学习笔记如下: #常见单行函数介绍(部分省略) #字符函数 #将姓变大写,名变小写,然后拼接。 SELECT CONCAT(UPPER(last_name), ,LOWER(first_name)) AS 姓名 FROM employees; # 姓名中首字符…...
百度百科词条怎么更新?怎么能顺利更新百科词条?
企业和个人百度百科词条的更新对于他们来说都具有重要的意义,具体如下: 对企业来说: 塑造品牌形象:百度百科是一个常被用户信任并参考的知识平台,通过更新企业词条可以提供准确、全面的企业信息,帮助企业塑…...
PPT怎么转换为PDF格式,收藏这两个在线工具。
PPT是一种常用的演示文稿格式,它可以包含丰富的动画效果和超链接,让你的内容更加生动和有趣。但是,如果你想将PPT分享给别人,或者在不同的设备上查看,你可能会遇到一些问题,比如: PPT文件太大&a…...
八大排序算法----堆排序
堆排序的基本步骤:(以从大到小的顺序排序为例) 1.构建大顶堆(每个结点的值都大于或等于其左右孩子结点的值) 2.排序:每次堆顶的元素取出来(整个堆中值最大),与最后一个…...
Docker Desktop 设置镜像环境变量
点击run 展开Optional settings container name :容器名称 Ports:根据你需要的端口进行输入,不输入则默认 后面这个 比如我这个 5432 Volumes:卷,也就是做持久化 需要docker 数据保存的地方 Environment variables…...
springboot之一:配置文件(内外部配置优先顺序+properties、xml、yaml基础语法+profile动态切换配置、激活方式)
配置的概念: Spring Boot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用application.properties或者application.yml(application.yaml)进行配置。 注意配置文件的命名必须是applicat…...
涛然自得周刊(第 5 期):蝲蛄吟唱的地方
作者:何一涛 日期:2023 年 8 月 20 日 涛然自得周刊主要精选作者阅读过的书影音内容,不定期发。历史周刊内容可以看这里。 电影 《沼泽深处的女孩》 改编自小说《蝲蛄吟唱的地方》,主角是一位在沼泽地独自生活并长大的女孩&…...
Android Ble蓝牙App(七)扫描过滤
Ble蓝牙App(七)扫描过滤 前言目录正文一、增加菜单二、使用MMKV① 添加依赖② 封装MMKV③ 使用MMKV 三、过滤空设备名四、过滤Mac地址五、过滤RSSI六、源码 前言 在上一篇文章中了解了MTU的相关知识以及对于设备操作信息的展示,本篇文章中将增…...
小程序当前页面栈以及跳转
1.调用页面栈刷新接口 let pages getCurrentPages(); //当前页面栈 if (pages.length > 1) { let beforePage pages[pages.length - 2]; //获取上一个页面实例对象 beforePage.$vm.getActivityLi…...
jQuery获取表单的值val()
(1)页面中有很多元素,包括表单中的输入项,如输入文本框等;获取、设置、输入文本框的值;val()方法。 (2)也包括<p>、<span>等元素;获取、设置这些元素的文本…...
【专栏必读】数字图像处理(MATLAB+Python)专栏目录导航及学习说明
文章目录 第一章:绪论第二章:数字图像处理基础第三章:图像基本运算第四章:图像的正交变换第五章:图像增强第六章:图像平滑第七章:图像锐化第八章:图像复原第九章:图像形态…...
2023年非证券类投资银行业发展报告
第一章 行业概况 非证券投资银行业是一个专门为公司、政府和高净值个人提供金融服务的行业,与传统的证券投资银行不同,其主要业务不涉及证券交易,而是注重为客户提供咨询服务、融资和投资管理等服务。 非证券投资银行通常涉及的业务领域包括…...
Matlab 如何把频谱图的纵坐标设置为分贝刻度
Matlab 如何把频谱图的纵坐标设置为分贝刻度 Matlab代码如下: % 如何把频谱图的纵坐标设置为分贝刻度 % % pr2_2_6 clc; clear; close all;load pr2_2_6_sndata1.mat % 读入数据 X fft(y); % FFT n2 1:L/21; % 计算正频率…...
VUE写后台管理(2)
VUE写后台管理(2) 1.环境2.Element界面3.Vue-Router路由后台1.左导航栏2.上面导航条 1.环境 1.下载管理node版本的工具nvm(Node Version Manager) 2.安装node(vue工程的环境管理工具):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 使用配置您的系统,以将这些位置用作默认存储库[rootclear ~]# cat …...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
