JavaEE(系列11) -- 多线程案例4(线程池)

news/2024/11/18 2:55:08/

目录

1. 线程池

2. 创建线程池

2.1 Executors类

2.2 ThreadPoolExecutor类

3. 自己实现线程池


1. 线程池

        线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认的堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间后创建另一个辅助线程但线程的数目永远不会超过最大值。超过最大值的线程可以排队,但他们要等到其他线程完成后才启动.

1.那么为什么要有线程池呢?

通俗的来讲,就是将线程提前准备好,创建线程不是直接从系统进行申请,而是从线程池里面拿,等待线程不用了,就放回池里.

  

2.为什么从线程池拿线程要比创建线程快呢?

这就涉及到用户态和内核态

 举例:

2. 创建线程池

2.1 Executors类

这是标准库中提供的创建线程池的方法

  1. 使用 Executors.newFixedThreadPool(10) 能创建出固定包含 10 个线程的线程池.
  2. 返回值类型为 ExecutorService
  3. 通过 ExecutorService.submit 可以注册一个任务到线程池中.
public class ExecutorsTest {public static void main(String[] args) {// 创建线程池,里面存放10个线程ExecutorService pool = java.util.concurrent.Executors.newFixedThreadPool(10);// 使用submit往线程池中提交若干的任务for (int i = 1; i <= 10; i++) {int number = i;pool.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello"+number);}});}}
}

Executors 创建线程池的几种方式

 

  1. newFixedThreadPool: 创建固定线程数的线程池
  2. newCachedThreadPool: 创建线程数目动态增长的线程池.
  3. newSingleThreadExecutor: 创建只包含单个线程的线程池.
  4. newScheduledThreadPool: 设定 延迟时间后执行命令,或者定期执行命令. 是进阶版的 Timer.

Executors 本质上是 ThreadPoolExecutor 类的封装. 

2.2 ThreadPoolExecutor类

 

拒绝策略

 最老的这个任务就是最先安排的任务.

代码示例:

public class threadPoolExecutorTest {public static void main(String[] args) {ExecutorService pool = new ThreadPoolExecutor(1,3,1000, TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>(),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());for (int i = 0; i < 3; i++) {pool.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello");}});}}
}

3. 自己实现线程池

  • 1. 使用堵塞队列来组织任务
  • 2.实现一个固定线程数数量的线程池
  • 3.使用submit方法,来往堵塞队列添加任务.
package ThreadPool;import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;/*** Created with IntelliJ IDEA.* Description:手动创建线程池* User: YAO* Date: 2023-05-18* Time: 15:21*/
public class MyThreadPool {// 1.内部使用阻塞队列实现,创建阻塞队列存放执行的任务private BlockingDeque<Runnable> queue = new LinkedBlockingDeque<>();// 2.创建往线程池推送出任务的方法public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);}//3. 创建构造方法,参数为线程的数量public MyThreadPool(int n){for (int i = 0; i < n; i++) {// 3.1 创建线程Thread t = new Thread(()->{try {while (true){// 此处需要有一个循环,就是无休止的取出,有任务就取出Runnable runnable = queue.take();runnable.run();}} catch (InterruptedException e) {throw new RuntimeException(e);}});// 3.2 不要忘记启动线程t.start();}}
}

测试自己创建的线程池

package ThreadPool;/*** Created with IntelliJ IDEA.* Description:测试自己构建的线程池* User: YAO* Date: 2023-05-18* Time: 15:29*/
public class MyThreadPoolTest {public static void main(String[] args) throws InterruptedException {// 1. 创建线程池实例MyThreadPool pool = new MyThreadPool(10);// 问题2: 当前代码,搞了一个10个线程的线程池,实际开发中,一个线程池的线程设置为多少合适?//答案:跟CPU有关系,并不是线程越多越好.不同的程序,线程的工作是不一样的.// 1.CPU密集型:主要做一些计算,要在CPU上运行.(此时线程数不应该超过CPU的核心数)// 2.IO密集型任务:主要等待IO操作(等待读写硬盘,读写网卡),不咋吃CPU(此时线程数可以远远超过CPU的核心数)// 2. 往线程池添加任务for (int i = 0; i < 1000; i++) {int number = i;// 问题1:  为什么需要使用Number进行接收i的值?// 答案:lambda表达式(本质就是匿名内部类的写法)具有变量捕获,匿名内部类也有变量捕获!!!!// 此处创建Number接收i的值,每一次循环都会创建Number一次,也就是在这个循环里面Number就是不变的,进行下一次循环就重新创建Numberpool.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello" + number);}});}Thread.sleep(1000);}
}

运行结果

1000个任务传入到阻塞队列,被此线程池的10个线程跑完了.

 


http://www.ppmy.cn/news/89011.html

相关文章

《四》Git 中的远程仓库

SSH 登录&#xff1a; 每个远程仓库都有两种地址&#xff1a;HTTPS 和 SSH。如果是 HTTPS 的地址&#xff0c;每次 push 的时候都要输入用户名和密码以校验身份。如果 SSH 的方式&#xff0c;就不再需要每次都输入用户名和密码了。 cd ~ 进入用户的家目录&#xff0c;执行 ss…

池州控股集团财务共享项目启动啦!

近日&#xff0c;由用友网络承建的池州市投资控股集团有限公司财务共享项目启动会成功举办&#xff0c;也标志着池州控股集团财务共享项目正式启动&#xff01;池州控股集团总经理刘俊、用友国资事业部总经理汪发清及其他相关专家和项目组主要成员参加了此次启动会。 池州投控集…

「实在RPA·人社数字员工」促进人力社保数字办公战略转型

一、人力社保部门数字化转型的重要性 伴随着国家放宽人力资源市场准入条例&#xff0c;多次出台相关扶持政策&#xff0c;市场竞争加剧&#xff0c;后疫情时代格局的大变局&#xff0c;如何提高服务质量和效率&#xff0c;如何降本增效&#xff0c;成为人力资源和社会保障行业…

2023年我要在深圳考CPDA数据分析师认证,含金量如何?

CPDA数据分析师认证是大数据方面的认证&#xff0c;助力数据分析人员打下扎实的数据分析基础知识功底&#xff0c;为入门数据分析保驾护航。 帮助数据分析人员掌握系统化的数据分析思维和方法论&#xff0c;提升工作效率和决策能力&#xff0c;遇到问题能够举一反三&#xff0c…

定时器试验

1.设计目的 &#xff08;1&#xff09;熟练运用汇编语言编程&#xff0c;并且掌握键盘查表来运行相应的功能 〔2〕熟悉启东硬件仿真系统&#xff0c;熟练应用该系统调试软件 〔3〕熟悉单片机应用系统的组成&#xff0c;并能运用程序控制外部流水灯 2.设计任务的内容和要求 〔1〕…

2023爱分析·中国面向开发者的低代码开发平台市场厂商评估报告

01 研究范围定义 “低代码”是一种可视化的应用开发方式&#xff0c;相对于传统编写代码的“纯代码”开发方式&#xff0c;低代码开发平台可以减少代码编写量或不使用代码编写进行应用的开发。随着技术革新&#xff0c;大模型也为低代码开发平台发展指明了新方向。从开发者与开…

leetcode203. 移除链表元素

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【LeetCode】 &#x1f353;希望我们一起努力、成长&#xff0c;共同进步。 题目链接 给你一个链表的头节点 head 和一个整数 val &…

qml使用基础

1 qml基本概念 qml和js一样是解析型语言&#xff0c;无需编译&#xff0c;在执行引擎中执行 The QML engine uses just-in-time (JIT) compilation to improve performance. It also caches the intermediate output to avoid having to recompile. qml引擎使用jit提高解释器性…