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

【Java ee初阶】多线程(7)

一、线程池

线程池的一些参数:

corePoolSize:核心线程数量

maximumPoolSize:核心线程数量+临时线程数量

上述是“java 的线程池策略”(其他语言,其他库的线程池可能不同)

keepAliveTime :临时线程的存活时间.临时线程允许摸鱼的最大时间

Timeunit:时间单位:秒/分钟/毫秒...

workQueue:线程池要完成的任务队列,每个任务都是通过Runnable来进行描述的

线程池在使用的时候,首先会创建一些线程,然后需要调用者给线程池放一些任务,这些线程就会从队列中取出任务,并且执行里面的代码。

(*工厂设计模式:正常创建一个对象是通过构造方法,new出来的。但是构造方法存在一定缺陷的,工厂模式就用来填补上这样的缺陷。不用构造方法来出池化对象,通过一组静态方法来初始化对象,静态方法就可以起不同的名字来做区分了。)

ThreadFactory:线程工厂 这个类就是Thread类的工厂类,由于在线程池中,是需要创建很多线程的,创建出来的线程需要进行哪些初始化操作?就可以通过threadFactory来进行设定。

实际上就是通过newThread方法,针对Thread对象进行初始化,再把这个Thread对象返回出来。比如想把线程池中的线程,按照一定的规则,设置name,或者想把线程池的线程全都设置成后台线程,或者都设置xxx为优先级。

例如,我想要将笛卡尔坐标系下的点转化为极坐标下的点表示,那么——

然而,多个版本的构造方法,需要“重载”,而重载要求方法名称相同但是参数列表不能相同,这里的参数列表相同,因此无法构成重载。那么此时的解决方法也就是:

这就是用来构造Point对象的类,也被称为“工厂类”

RejectedExecutionHandler:拒绝策略

线程池,有任务列表、阻塞队列,当任务队列满了的时候,如果再次添加新的任务,会发生什么呢?

正常来说,除非特殊说明,我们写的代码是不希望有这种突发性的阻塞的,因为这种阻塞稍不留神可能就对程序造成不可预估的影响。

因此直接让添加任务的线程阻塞,其实是不太好的,不太好就意味着要有其他的方法——因此标准库的线程池就引入了“拒绝策略”

正常情况下,是线程池里面的线程执行任务的,但是现在线程池里面的线程忙不过来了,就只能由调用者自己找个线程来执行任务

标准库中提供了一个对ThreadPoolExecutor进行了封装的简化版本Executors,本质上也是工厂类,提供了一些工厂方法,对上述的ThreadPoolExecutor进行不同的初始化。

这里的工厂方法,就是在创建不同风格的线程池。

package Thread;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class demo39 {public static void main(String[] args) {//固定线程数目的线程池,核心线程数和最大线程数都是4ExecutorService executorService = Executors.newFixedThreadPool(4);//核心线程数设置为0,最大线程数设为一个Int最大值这样的线程池ExecutorService executorService1 = Executors.newCachedThreadPool();//固定只有一个线程的线程池(这个东西确实用的不多,可以通过这种方式来代替创建线程的方式)ExecutorService executorService2 = Executors.newSingleThreadExecutor();//这个线程池,本质上是一个定时器,放到这个线程池中的任务,会在一定时间之后执行ExecutorService executorService3 = Executors.newScheduledThreadPool(4);}}

现在我们来让这个线程池来执行一些任务,为了更清晰地看出这个任务做了10次,我们来对i进行打印。然而这里不能直接这么些,会出现“变量捕获”的问题。

这里通过这种方法来进行解决。

有些公司更加想要完全体的ThreadPoolExecutor,可控性更强。

如果队列中没有其他的任务,take就会阻塞,一直阻塞到其他线程执行submit为止

package Thread;import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;class MyFixedThreadPool{ // 固定线程池。private BlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue<Runnable>(); // 阻塞队列,用于存放任务。public MyFixedThreadPool(int n){ // 构造方法,初始化线程池。for(int i = 0; i < n; i++){ // 创建n个线程。Thread t = new Thread(()->{ // 创建线程。try {while (true) {Runnable task = blockingQueue.take(); // 从阻塞队列中取出任务。task.run(); // 执行任务。}} catch (Exception e) {// TODO: handle exceptione.printStackTrace();}    });t.start();    }       
}public void submit(Runnable task) throws Exception{ // 提交任务。// 1. 将任务放入阻塞队列。blockingQueue.put(task);}
}public class demo40 {public static void main(String[] args) throws Exception {// TODO Auto-generated method stubMyFixedThreadPool myFixedThreadPool = new MyFixedThreadPool(100); // 创建线程池。for(int i = 0; i < 10; i++){ // 提交1000个任务。int finalI = i; // 闭包。myFixedThreadPool.submit(()->{ // 提交任务。System.out.println("任务" + finalI + "正在执行"); // 打印任务正在执行。});}}}

二、定时器

定时器在java编程中是一个非常终于熬的组件。

阻塞队列,太重要了,太常用了,在实际工作中,会把阻塞队列单独封装成一个/一组服务器

定时器也是类似,也会被单独封装成一个/一组服务器,类似于闹钟。

为什么需要定时器呢?——编程中有些任务,不需要立即执行,而是要等一会儿,等到到一定时间的时候再去执行。

Java标准库提供了Timer这样的类,可以通过他来实现简单的定时器。

一开始输出:程序启动,过了4s之后输出“定时器执行任务”

自行实现一个定时器

package Thread;import java.util.PriorityQueue;class MyTimerTask implements Comparable<MyTimerTask>{private Runnable task;private long delay;private long time ;public MyTimerTask(Runnable task, long delay){this.task = task;this.time = delay + System.currentTimeMillis();}public Runnable getTask(){return task;}public long getTime(){return time;}public int compareTo(MyTimerTask o){ // 比较两个任务的时间,谁的时间小谁排在前面。return (int)(this.time - o.time); // 比较两个任务的时间,谁的时间小谁排在前面。} // 比较两个任务的时间,谁的时间小谁排在前面。
}//自己实现定时器
//定时器能够同时管理多个任务
//有一定的数据结构来组织这多个任务
//ArrayList不太合适
//更好的选择是优先级队列class MyTimer{private PriorityQueue<MyTimerTask> queue = new PriorityQueue<MyTimerTask>();private static Object locker = new Object();public MyTimer(){//创建线程Thread t = new Thread(()->{ // 线程的任务是不断地从队列中取出任务,并执行。while (true) {try { // 捕获异常。synchronized(locker){ // 出队列。if(queue.isEmpty()){locker.wait();}MyTimerTask task = queue.peek(); // 取出队列中的第一个任务。long curTime = System.currentTimeMillis(); // 获取当前时间。if(curTime < task.getTime()){ // 如果当前时间小于任务的时间,说明任务还没有到执行时间。locker.wait(task.getTime() - curTime);}else{queue.poll(); // 取出队列中的第一个任务。task.getTask().run(); // 执行任务。}}} catch (InterruptedException e) { // 捕获异常。e.printStackTrace(); // 打印异常栈。}}});t.start(); // 启动线程。}public void schedule(Runnable task, long delay){ synchronized(locker){ // 入队列。queue.offer(new MyTimerTask(task, delay)); // 入队列。locker.notify(); // 唤醒线程。} // 入队列。}
}public class demo42 {public static void main(String[] args) {MyTimer timer = new MyTimer(); // 创建定时器。timer.schedule(new Runnable() {@Overridepublic void run() { // 任务的执行逻辑。System.out.println("定时任务 3000"); // 打印出 hello world。}}, 3000);timer.schedule(new Runnable() {@Overridepublic void run() { // 任务的执行逻辑。System.out.println("定时任务 2000"); // 打印出 hello world。}}, 2000);        timer.schedule(new Runnable() {@Overridepublic void run() { // 任务的执行逻辑。System.out.println("定时任务 1000"); // 打印出 hello world。}}, 1000);}}

相关文章:

  • 学习路线(python)
  • 大模型基础(四):transformers库(上):pipline、模型、分词器
  • [Linux] 笔记本访问b站,Linux内核打印的调用栈
  • 五一假期作业
  • android-ndk开发(4): linux开发机有线连接android设备
  • Go小技巧易错点100例(二十九)
  • 关于毕业论文,查重,AIGC
  • 【漫话机器学习系列】240.真正类率(True Positive Rate,TPR)
  • C++演讲比赛案例代码
  • AI日报 · 2025年5月05日|雅诗兰黛与微软合作成立 AI 创新实验室,加速美妆产品研发与营销
  • LCD,LED
  • AI笔记-1
  • 稀疏性预测算法初步
  • 文心一言开发指南13——文心一言API两种调用方式的区别
  • cpp学习笔记1--class
  • 【QT】QT安装
  • Python生活手册-NumPy数组创建:从快递分拣到智能家居的数据容器
  • Springboot循环依赖
  • React-router v7 第八章(边界处理)
  • AI向量检索
  • 有乘客被高铁车门夹住?铁路回应:系突感不适下车,未受伤,列车正点发车
  • “子宫肌瘤男性病例”论文后:“宫颈癌、高危产妇”论文也现男性病例,作者称“打错了”
  • “五一”假期预计全社会跨区域人员流动累计14.67亿人次
  • 工程机械行业景气度持续回升,三大龙头一季度营收、净利双增
  • 《开始推理吧3》:演员没包袱,推理更共情
  • 五问舆论漩涡中的“协和‘4+4’模式”:是否公平,如何合格?