Java线程池及Thread相关问题

Java线程池及Thread相关问题

  • 一、Java线程池有哪些核心参数,分别有什么的作用?
  • 二、线程池有哪些拒绝策略?
  • 三、线程池的执行流程?
  • 四、线程池核心线程数怎么设置呢?
    • 方式一
    • 方式二
    • 基本原则
  • 五、ThreadLocal底层是怎么实现的?
  • 六、ThreadLocal为什么会内存泄漏?
  • 七、sleep()和wait()有什么区别?
  • 八、多个线程如何保证按顺序执行?
  • 九、Java线程池中submit()和execute()方法有什么区别?

一、Java线程池有哪些核心参数,分别有什么的作用?

构造方法最多的是7个参数;

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( 8, 16, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1024), Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy() );
    public static void main(String[] args) {//基于Executor框架实现线程池ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(8,16,60,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(1024),Executors.defaultThreadFactory(),//new MyThreadFactory("my-thread-pool-"),new ThreadPoolExecutor.AbortPolicy());//创建线程池后,初始化一个核心线程//threadPoolExecutor.prestartCoreThread();//创建线程池后,初始化所有的核心线程//threadPoolExecutor.prestartAllCoreThreads();//设置核心线程在空闲超时后是否允许销毁,true表示允许销毁threadPoolExecutor.allowCoreThreadTimeOut(true);threadPoolExecutor.execute(() -> {System.out.println("任务执行......" + Thread.currentThread().getName());});threadPoolExecutor.shutdown();}static class MyThreadFactory implements ThreadFactory {private final AtomicInteger threadNumber = new AtomicInteger(1); //线程编号private final String namePrefix; //线程名称的前缀public MyThreadFactory(String namePrefix) {this.namePrefix = namePrefix;}@Overridepublic Thread newThread(Runnable r) {Thread t = new Thread(r, namePrefix + threadNumber.getAndIncrement());if (t.isDaemon())t.setDaemon(false);if (t.getPriority() != Thread.NORM_PRIORITY)t.setPriority(Thread.NORM_PRIORITY);return t;}}
  1. int corePoolSize

线程池中的核心线程数量
allowCoreThreadTimeOut;允许核心线程超时销毁;
boolean prestartCoreThread(),初始化一个核心线程;
int prestartAllCoreThreads(),初始化所有核心线程;

  1. int maximumPoolSize

线程池中允许的最大线程数,当核心线程全部繁忙且任务队列存满之后,线程池会临时追加线程,直到总线程数达到maximumPoolSize这个上限;

  1. long keepAliveTime

线程空闲超时时间,如果一个线程处于空闲状态,并且当前的线程数量大于corePoolSize,那么在指定时间后,这个空闲线程会被销毁;

  1. TimeUnit unit

keepAliveTime的时间单位 (天、小时、分、秒…);

  1. BlockingQueue<Runnable> workQueue

任务队列,当核心线程全部繁忙时,任务存放到该任务队列中,等待被核心线程来执行;

  1. ThreadFactory threadFactory

线程工厂,用于创建线程,一般采用默认的线程工厂即可,也可以自定义实现;
Executors.defaultThreadFactory(),
Executors.privilegedThreadFactory(),

  1. RejectedExecutionHandler handler

拒绝策略(饱和策略),当任务太多来不及处理时,如何 “拒绝” 任务?
1、核心线程corePoolSize正在执行任务;
2、线程池的任务队列workQueue已满;
3、线程池中的线程数达到maximumPoolSize时;
就需要 “拒绝” 掉新提交过来的任务;

二、线程池有哪些拒绝策略?

JDK提供了4种内置的拒绝策略:AbortPolicyCallerRunsPolicyDiscardOldestPolicyDiscardPolicy

  • 1、AbortPolicy(默认):丢弃任务并抛出RejectedExecutionException异常,这是默认的拒绝策略;
  • 2、DiscardPolicy:直接丢弃任务,不抛出异常,没有任何提示;
  • 3、DiscardOldestPolicy:丢弃任务队列中靠最前的任务,当前提交的任务不会丢弃;
  • 4、CallerRunsPolicy: 交由任务的调用线程(提交任务的线程)来执行当前任务;
  • 除了上面的四种拒绝策略,还可以通过实现RejectedExecutionHandler接口,实现自定义的拒绝策略;

三、线程池的执行流程?

在这里插入图片描述

当提交一个新任务到线程池时,具体的执行流程如下:

  1. 当我们提交任务,线程池会根据corePoolSize大小创建线程来执行任务;
  2. 当任务的数量超过corePoolSize数量,后续的任务将会进入阻塞队列阻塞排队;
  3. 当阻塞队列也满了之后,那么将会继续创建(maximumPoolSize-corePoolSize)个数量的线程来执行任务,如果任务处理完成,maximumPoolSize-corePoolSize个额外创建的线程等待 keepAliveTime之后被自动销毁;
  4. 如果达到maximumPoolSize,阻塞队列还是满的状态,那么将根据不同的拒绝策略进行拒绝处理;

四、线程池核心线程数怎么设置呢?

方式一

在这里插入图片描述
Ncpu = cpu的核心数 ,Ucpu = cpu的使用率(在0~1之间),W = 线程等待时间,C = 线程计算时间

举例

  • 8 * 100% * (1+60/40) = 20
  • 8 * 100% * (1+80/20) = 40

方式二

任务分为CPU密集型和IO密集型
在这里插入图片描述

  1. CPU密集型

线程数 = CPU核心数 + 1;

  • 这种任务主要是消耗CPU资源, 比如像加解密、压缩、计算等一系列需要大量耗费 CPU 资源的任务;
  • +1,比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断,或者其它原因导致的任务暂停而带来的影响。一旦任务暂停,CPU 就会处于空闲状态,而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间;
  1. IO密集型

线程数 = CPU核心数 * 2;

  • 这种任务会有大部分时间在进行 IO 操作,比如像 MySQL 数据库、文件读写、网络通信等任务,这类任务不会特别消耗CPU资源,但是 IO 操作比较耗时,会占用比较多时间;
  • 线程在处理 IO 的时间段内不会占用 CPU,这时就可以将 CPU 交出给其它线程使用,因此在 IO 密集型任务的应用中,可以多配置一些线程;

基本原则

  • 1、线程执行时间越多,就需要越少的线程;
  • 2、线程等待时间越多,就需要越多的线程;
  • 以上理论参考依据,实际项目中建议在本地或者测试环境进行压测多次调整线程池大小,找到相对理想的值大小;

五、ThreadLocal底层是怎么实现的?

在这里插入图片描述

六、ThreadLocal为什么会内存泄漏?

  • ThreadLocal是一个类似于HashMap的数据结构;

  • ThreadLocal的实现原理就是通过set把value set到线程的threadlocals属性中,threadlocals是一个Map,其中的key是ThreadLocal的this引用,value是我们所set的值;

在使用线程池的时候,可能由于线程没有结束,ThreadLocalMap对象的 Entry[] 数组中的数据没有被回收,内存没有释放,那么当线程执行大量数据时,可能导致内存溢出,数据泄露。

七、sleep()和wait()有什么区别?

(1) 所属类不同;

  • sleep 是Thread的;
  • wait 是Object的;
Thread.sleep(1000);Object object = new Object();
object.wait();

(2) 方法类型不用;

  • sleep 是静态方法;
  • wait 是实例方法;

(3) 使用语法不同;

  • sleep 可以直接使用
  • wait 获取锁之后,才可以使用,不然会报错;

(4) 唤醒方式不同;

  • sleep 设置时间过期后自动唤醒;
  • wait 可以设置过期时间,也可以使用notify()或notifyAll()方法唤醒;

(5) 释放锁资源不同;

  • sleep 自动释放锁;
  • wait 不会自动释放锁;

(6) 线程状态不同

  • sleep 状态:TIMED_WAITING
  • wait 状态:WAITING

八、多个线程如何保证按顺序执行?

比如任务B,它需要等待任务A执行之后才能执行,任务C需要等待任务B执行之后才能执行;

1、通过join()方法使当前线程 “阻塞”,等待指定线程执行完毕后继续执行;

    public static void main(String[] args) throws Exception {// t1线程Thread t1 = new Thread(() -> {System.out.println(Thread.currentThread().getName() + " 执行");}, "t1");// t2线程Thread t2 = new Thread(() -> {try {t1.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 执行");}, "t2");// t3线程Thread t3 = new Thread(() -> {try {t2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 执行");}, "t3");t1.start();t2.start();t3.start();}

或者:

    public static void main(String[] args) throws Exception {// t1线程Thread t1 = new Thread(() -> {System.out.println(Thread.currentThread().getName() + " 执行");}, "t1");// t2线程Thread t2 = new Thread(() -> {System.out.println(Thread.currentThread().getName() + " 执行");}, "t2");// t3线程Thread t3 = new Thread(() -> {System.out.println(Thread.currentThread().getName() + " 执行");}, "t3");t1.start();t1.join();t2.start();t2.join();t3.start();}

2、通过创建单一化线程池newSingleThreadExecutor()实现;

    // 自定义线程池private static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(1024),Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardOldestPolicy());// 线上环境不推荐使用这种方式(阿里巴巴编码规范不推荐使用)private static ExecutorService executorService = Executors.newSingleThreadExecutor();public static void main(String[] args) throws Exception {// t1线程Thread t1 = new Thread(() -> {System.out.println(Thread.currentThread().getName() + " t1执行");}, "t1");// t2线程Thread t2 = new Thread(() -> {System.out.println(Thread.currentThread().getName() + " t2执行");}, "t2");// t3线程Thread t3 = new Thread(() -> {System.out.println(Thread.currentThread().getName() + " t3执行");}, "t3");threadPoolExecutor.execute(t1);threadPoolExecutor.execute(t2);threadPoolExecutor.execute(t3);threadPoolExecutor.shutdown();}

3、通过倒数计时器CountDownLatch实现;

    /** 用于判断t1线程是否执行,倒计时设置为1,执行后减1 */private static final CountDownLatch countDownLatch1 = new CountDownLatch(1);/** 用于判断t2线程是否执行,倒计时设置为1,执行后减1 */private static final CountDownLatch countDownLatch2 = new CountDownLatch(1);public static void main(String[] args) throws Exception {// t1线程Thread t1 = new Thread(() -> {System.out.println(Thread.currentThread().getName() + " 执行");countDownLatch1.countDown(); // -1}, "t1");// t2线程Thread t2 = new Thread(() -> {try {countDownLatch1.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 执行");countDownLatch2.countDown();}, "t2");// t3线程Thread t3 = new Thread(() -> {try {countDownLatch2.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + " 执行");}, "t3");t1.start();t2.start();t3.start();}

4、使用Object的wait/notify方法实现;

5、使用线程的Condition(条件变量)方法实现;

6、使用线程的CyclicBarrier(回环栅栏)方法实现;

7、使用线程的Semaphore(信号量)方法实现;

九、Java线程池中submit()和execute()方法有什么区别?

(1) 两个方法都可以向线程池提交任务;

    public static void main(String[] args) {ExecutorService executorService = Executors.newSingleThreadExecutor();executorService.execute(() -> {System.out.println("任务开始..................");int a = 10 / 0;System.out.println("任务结束..................");});executorService.submit(() -> {System.out.println("任务开始..................");int a = 10 / 0;System.out.println("任务结束..................");});executorService.shutdown();}

(2) execute 只能提交Runnable,无返回值;

(3) submit 既可以提交Runnable,返回值为null,也可以提交 Callable,返回值 Future

(4) execute()方法定义在Executor接口中;

(5) submit()方法定义在ExecutorService接口中;
在这里插入图片描述

(6) execute执行任务时遇到异常会直接抛出;

(7) submit执行任务时遇到异常不会直接抛出,只有在调用Futureget()方法获取返回值时,才会抛出异常;

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SoraAI优先体验资格注册教程

SoraA1视频工具优先体验资格申请 申请网址&#xff1a;https://openai.com/form/red-teaming-network 申请步骤&#xff1a; 填写基础信息 请使用英文根据内容填写以下内容&#xff0c;名、姓、电子邮件、居住国家、组织隶属关系(如果有)、教育水平 、学位&#xff08;哪个领…

利用Python副业赚钱,看完这篇你就懂了!

Python都可以做哪些副业&#xff1f; 1、兼职处理数据Excel整理数据功能虽然很强大&#xff0c;但在Python面前&#xff0c;曾经统治职场的它也的败下阵来。因为Python在搜集数据整理分析数据的过程中更加便捷&#xff0c;通过几行代码还可以实现自动化操作。 如果你学会Pyth…

指针运算笔试题解析

题目1&#xff1a; int main() { int a[5] { 1, 2, 3, 4, 5 }; int* ptr (int*)(&a 1); printf("%d %d", *(a 1), *(ptr - 1)); return 0; } ptr中存放了整个数组的地址&#xff0c;ptr是int*类型&#xff0c;&a1跳到5的地址后又被强制类…

EasyX的学习2

消息处理——漂亮的按钮(鼠标) 用到的函数 1.消息结构体变量类型&#xff1a;使用ExMessage ExMessage msg{ 0 }; 定义一个变量名为msg的ExMessage结构体变量并初始化为0 2.获取消息函数&#xff1a;peekmessage函数 //获取消息 peekmessage(&msg, EX_MOUSE); 两个参…

【打工日常】使用docker部署在线Photopea用于linux下替代ps

一、Photopea介绍 linux没有ps适配&#xff0c;对于有时候工作来说确实不方便&#xff0c;我找了很久&#xff0c;才找到了一款功能可以跟ps接近的在线软件&#xff0c;使用docker部署就可以了。它是ps的最佳替代品之一&#xff0c;其界面几乎与ps相同&#xff0c;只不过它是在…

MySQL基础-----SQL语句之DCL数据控制语句

目录 前言 一、管理用户 1.查询用户 2.创建用户 3.修改用户密码 4.删除用户 案例 二、权限控制 1.查询权限 2.授予权限 3.撤销权限 案例 前言 本期我们学习SQL语句的最后一部分内容&#xff0c;也就是数据控制语句DCL。DCL英文全称是Data Control Language(数据控制语…

鱼哥赠书活动第12期:《基于React低代码平台开发》

鱼哥赠书活动第12期&#xff1a;《基于React低代码平台开发》 一、React与低代码平台的结合优势二、基于React的低代码平台开发挑战三、基于React的低代码平台开发实践四、未来展望内容简介&#xff1a;作者简介如何阅读&#xff1a;适合阅读人群&#xff1a;赠书抽奖规则:往期…

DMA 链表模式(LLI)深度解析

在进行一次 DMA 读或者写的时候&#xff0c;可以配置多个链表&#xff0c;从而当一个链表的数据传输完成时&#xff0c;会跳到下一个链表的起始地址&#xff0c;并继续传输数据&#xff0c;直到链表的下一个地址为 0。如果 DMA 使能了完成中断&#xff0c;则当 DMA 发送或者接收…

15 实战:Kaggle房价预测 + 课程竞赛:加州2020年房价预测【李沐动手学深度学习课程笔记】

15 实战&#xff1a;Kaggle房价预测 课程竞赛&#xff1a;加州2020年房价预测【李沐动手学深度学习课程笔记】https://zhuanlan.zhihu.com/p/685343754 写在前面&#xff1a;这里格式很乱&#xff0c;代码直接去知乎copy 1 实战Kaggle比赛&#xff1a;预测房价 1.1 实现几个函…

【源码】imx6ull实现触摸屏单点实验-移植tslib和qt

一、本实验实验的器材&#xff1a; 1.正点原子imx6ull的阿尔法开发板v2.2 2.屏幕ALIENTEK 4.3 RGBLCD 二、实验已经移植好的文件&#xff1a; 仓库代码&#xff1a;https://gitee.com/wangyoujie11/atkboard_-linux_-driver.git 1.文件说明 arm-qt.tar.bz2&#xff1a;移植好的…

基于SSM的农业信息管理系统的设计与实现(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的农业信息管理系统的设计与实现&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;…

Mint_21.3 drawing-area和goocanvas的FB笔记(四)

Cairo图形输出 cairo的surface可以是pixbuf, 可以是screen, 可以是png图&#xff0c;也可以是pdf文件 、svg文件、ps文件&#xff0c;定义了surface就可以用cairo_create(surface)产生cairo context, 操作cairo context就可以方便地在surface上画图&#xff0c;如果surface是p…

Linux基本命令

一、基本命令 修改mysql端口号 vim /etc/my.cnf云服务器ssh端口修改 vim /etc/ssh/sshd_config1.1 关机和重启 关机 shutdown -h now 立刻关机 shutdown -h 5 5分钟后关机 poweroff 立刻关机重启 shutdown -r now 立刻重启 shutdown -r 5 5分钟后重启 reboot 立刻重启1.2…

使用mysqld --install命令时出现MSVCR120.dll文件丢失错误

Visual C 2013 and Visual C Redistributable Package https://support.microsoft.com/en-us/help/3179560/update-for-visual-c-2013-and-visual-c-redistributable-package 进去之后先找到自己的版本&#xff0c;x64还是x86&#xff0c;下载 vcredit &#xff0c;进行安装即…

小程序固定头部:CSS实现

效果图 代码逻辑&#xff1a;设置头部的高度&#xff0c;浮动固定后&#xff0c;再加个这个高度的大小的外边距 .weui-navigation-bar {position: fixed;top: 0px;left: 0px;right: 0px;height:90px; } .weui-navigation-bar_bottom{height:90px; }

高转化利器】Xinstall实现H5唤醒App,打开指定页面,轻松满足营销需求!

在移动互联网时代&#xff0c;App的拉新促活对于企业的发展至关重要。为了提升用户体验和转化率&#xff0c;Xinstall推出了一项强大的功能——H5唤醒App。通过这一功能&#xff0c;用户可以直接从Web页面拉起App&#xff0c;并在拉起过程中通过传参打开指定页面&#xff0c;满…

【Vue3】Hooks:一种全新的组件逻辑组织方式

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

MATLAB环境下基于离散小波变换的体外血管图像处理

下面简要介绍小波变换的部分应用。 信号去噪。小波去噪是根据有效信号和噪声信号在小波变换后表现出的不同特性实现的&#xff0c;一般可用于去除语音、图像、视频等中的噪声信号。小波去噪方法根据对小波系数的非线性处理方式分为三类&#xff0c;分别是小波变换模极大值去噪…

qt QRadioButton 及QButtonGroup 使用

QRadioButton 放在组合框QGroupBox中&#xff0c;再点击时&#xff0c;即使有多个QRadioButton按钮&#xff0c;同时选中的也就只有一个。 如下图所示&#xff0c; 对于多个QRadioButton&#xff0c;每个按钮都写一个槽函数是不太明智的选择&#xff0c;需要将QRadioButton放在…

【LeetCode:2917. 找出数组中的 K-or 值 + 模拟+位运算】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…