javaEE初阶————多线程初阶(5)

本期是多线程初阶的最后一篇文章了,下一篇就是多线程进阶的文章了,大家加油!

一,模拟实现线程池

我们上期说过线程池类似一个数组,我们有任务就放到线程池中,让线程池帮助我们完成任务,我们该如何实现线程池呢,我们来想一想线程的构造方法,第一个参数是核心线程数,第二个是最大线程数,这个我们不考虑,第三个是最大空闲时间,第四个事枚举的时间类型,第五个是阻塞队列,完了是工厂模式,之后是拒绝策略;

我们来模拟一下;

package Demo1;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;public class MyThreadPool {private BlockingQueue<Runnable> queue = null;public MyThreadPool(int n){queue = new ArrayBlockingQueue<>(n);for (int i = 0; i < n; i++) {Thread t  = new Thread(()->{while(true){try {queue.take().run();} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();}}public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);}
}

我们先来看这段代码,我们先起了类名MyThreadPool,在类中先弄了一个未初始化的阻塞队列,在创建构造方法,由传入的数字来创建阻塞队列的容量也就是线程池中有几个线程,我们根据传入的数字n来创建n个线程,让n个线程循环往复的到阻塞队列中去哪任务,还有submit方法,我们让将拿到的任务添加到阻塞队列中去,我们来测试代码; 

public class test {public static void main(String[] args) throws InterruptedException {MyThreadPool pool = new MyThreadPool(4);for (int i = 0; i < 50; i++) {int id = i;pool.submit(()->{System.out.println(id + " and " + 123456);});}}
}

我们创建了50个任务,让线程池来完成,我们看看运行结果;

我们看到线程随机执行了我们的任务;

最后是没有结束的啊,没有正常的返回值,这是因为我new thread创建的线程是前台线程,那几个线程还在阻塞着等待任务呢,我们想要结束应该把他们设置为后台线程才行;

———————————————————————————————————————————

二,定时器详解

定时器是什么,定时器也是软件开发中的一个重要组件,它有什么用的,大家使用浏览器的时候有没有发生过连接断开或者未响应之类的情况,其实这就是定时器在发挥,如果没有定时器的话就会一直请求,但是没准这次的请求就不会得到响应,为了不发生无休止的等待,我们就使用定时器来中断这次请求,既然响应不了那就直接结束;

那么我们如何使用定时器呢?

标准库中提供了Timer类,Timer类中包含一个schedule方法,我们使用schedule方法来使用定时器功能,schedule方法中有两个参数,一个是需要执行的任务;

schedule(new TimerTask(抽象类,继承了Runnable接口),时间);

我们来用代码展示一下;

import java.util.Timer;
import java.util.TimerTask;public class test {public static void main(String[] args) throws InterruptedException {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("1s后   任务1");}},1000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("3s后   任务2");}},3000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("5s后   任务3");}},5000);Thread.sleep(7000);timer.cancel();}
}

 我们给Timer三个任务让他在规定时间段运行,并最终终止Timer线程,我们来看运行效果;

                                                                                                                   

另外,Timer其实已经过时,

我推荐使用更强的scheduledExecutorService,Timer是单线程的,但是scheduledExecutorService是线程池,功能更强,我们来说说用法;

1,延迟执行任务

schedule(Runnable command,long delay,TimeUnit unit)

第一个参数是任务,就是接口就行,第二个参数是时间,意思是多长时间执行任务,达到延迟效果,第三个参数是时间类型,也就是枚举类型;

我们来上代码;

这是第三个参数枚举类型,提供了很多的枚举;

 

public class Test2 {public static void main(String[] args) {ScheduledExecutorService sr = Executors.newScheduledThreadPool(1);sr.schedule(()->{System.out.println("2秒后    打印");},2, TimeUnit.SECONDS);sr.schedule(()->{System.out.println("4秒后    打印");},4,TimeUnit.SECONDS);sr.shutdown();}
}

我们使用shutdown方法来关闭调度器,来看运行结果;

程序正常结束了;

2,定期执行任务

scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)

第一个参数还是接口任务,第二个参数是初始延迟时间,第三个参数是任务执行的时间间隔,最后一个参数还是时间的枚举类型;

我们来上代码;

public class Demo2 {public static void main(String[] args) throws InterruptedException {ScheduledExecutorService service = Executors.newScheduledThreadPool(1);service.scheduleAtFixedRate(()->{System.out.println("任务执行了");},1,2, TimeUnit.SECONDS);Thread.sleep(10000);service.shutdown();}
}

  

还有一种固定时间延迟执行任务,跟这个是基本一样的,

schedulewithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)

第一个参数还是接口任务,第二个参数是初始延迟时间,第三个参数是任务执行的延迟时间,最后一个参数还是时间的枚举类型;

 

public class Demo3 {public static void main(String[] args) throws InterruptedException {ScheduledExecutorService service = Executors.newScheduledThreadPool(1);service.scheduleWithFixedDelay(()->{System.out.println("任务执行了");},1,2, TimeUnit.SECONDS);Thread.sleep(10000);service.shutdown();}
}

 这两个有啥区别呢,感觉是很像的,第一个scheduleAtFixedRate是延迟一定时间后按固定的时间来执行,这个是严格执行的,不会根据任务执行的时间来往后推,如果这个任务执行了1s那么距离规定的时间就还剩1s了,如果使用schedulewithFixedDelay的就是延迟执行,如果我们这个任务执行了1s那么距离执行下一个任务的时间还是2s,另外scheduledExecutorService因为是基于线程池实现,所以在发生异常时是不会终止的,而单线程的Timer是会随着异常而终止的;

讲了这么多了,我们来模拟实现一下定时器吧,

首先为我们来思考一下怎么实现呢,我们要创建一个MyTimer类,其中包含我们要使用的优先级队列,我们来实现Schedule方法,实现将任务和要执行的时间,还要实现Mytimer中有线程来执行任务,之后还有实现任务类,我们来试试;

1,先来任务类:

public class TimerTask implements Comparable<TimerTask>{private long time;private Runnable task;public TimerTask(long time,Runnable runnable){this.time = time;this.task = runnable;}@Overridepublic int compareTo(TimerTask o) {return (int)(this.time-o.time);}public void run(){task.run();}public long getTime(){return time;}
}

任务类中有记录的时间long类型的time,一个Runnable任务,在任务初始化的时候把时间和任务都初始化了,实现run方法和getTime方法,在实现comparable接口为了优先级队列做准备,我们想要把小的时间先执行,再来MyTimer


public class MyTimer {private PriorityQueue<TimerTask> priorityQueue = new PriorityQueue<>();Object locker = new Object();public void schedule(Runnable runnable,long time){TimerTask timerTask = new TimerTask(System.currentTimeMillis()+time,runnable);synchronized (locker){priorityQueue.offer(timerTask);locker.notify();}}public MyTimer(){Thread t = new Thread(()->{while(true){synchronized (locker){while(priorityQueue.isEmpty()){try {locker.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}TimerTask task = priorityQueue.peek();if (task.getTime()>System.currentTimeMillis()){try {locker.wait(task.getTime()-System.currentTimeMillis());} catch (InterruptedException e) {throw new RuntimeException(e);}}else{task.run();priorityQueue.poll();}}}});t.start();}
}

初始化一个优先级队列,大堆还是小堆要在TimerTask中的compareTo中修改,实现schedule方法,创建一个任务对象,参数的任务用传入的,时间用当前入队列的时间戳加上传入的时间,之后将任务放到队列中去,因为优先级队列是不安全的,我们要在入队列的时候加锁,接下来就是线程,我们在MyTimer构造方法中,创建一个线程,之后让线程循环的去队列中取得任务,这里因为还是涉及优先级队列,所以我们还是要加锁,我们要循环判断队列是否为空,为啥要使用循环,因为要避免入队列操作的notify唤醒当前的wait之后,另一个线程抢先执行了任务,但是当前的线程就会去peek空的队列了,所以我们循环判断,就是为了要避免误唤醒,我们在拿到了任务之后,如果当前时间还没到我们要执行的时间我们就用wait(定时)来等待指定时间来继续执行,我们这里不用sleep,之前说过,我们基本是不会使用sleep的因为sleep会抱着锁睡,虽然不占用Cpu资源了,但是就这么停着,不符合我们预期的;

public class test {public static void main(String[] args) throws InterruptedException {MyTimer myTimer = new MyTimer();myTimer.schedule(()->{System.out.println("已经过了2秒 执行任务");},2000);myTimer.schedule(()->{System.out.println("已经过了5秒 执行任务");},5000);}
}

我们来测试一下;

自己观察一下,会根据时间来运行的,本期文章就到这里啦;

大家继续加油!

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

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

相关文章

工业AR眼镜的‘芯’动力:FPC让制造更智能【新立电子】

随着增强现实&#xff08;AR&#xff09;技术的快速发展&#xff0c;工业AR智能眼镜也正逐步成为制造业领域的重要工具。它不仅为现场工作人员提供了视觉辅助&#xff0c;还极大地提升了远程协助的效率、优化了仓储管理。FPC在AI眼镜中的应用&#xff0c;为工业AR智能眼镜提供了…

FPGA开发,使用Deepseek V3还是R1(5):temperature设置

以下都是Deepseek生成的答案 FPGA开发&#xff0c;使用Deepseek V3还是R1&#xff08;1&#xff09;&#xff1a;应用场景 FPGA开发&#xff0c;使用Deepseek V3还是R1&#xff08;2&#xff09;&#xff1a;V3和R1的区别 FPGA开发&#xff0c;使用Deepseek V3还是R1&#x…

网站内容更新后百度排名下降怎么办?有效策略有哪些?

转自 网站内容更新后百度排名下降怎么办&#xff1f;有效策略有哪些&#xff1f; 网站内容更新是促进网站优化的关键环节&#xff0c;但是频繁修改网站内容会对网站的搜索引擎排名造成很大的影响。为了保持网站排名&#xff0c;我们需要采取一些措施来最小化对百度排名的影响。…

安装 cpolar 内网穿透工具的步骤

安装 cpolar 内网穿透工具的步骤 1. 下载 cpolar 软件安装包 步骤&#xff1a; 前往 cpolar 官方下载页面。 根据您的操作系统&#xff08;Windows、macOS、Linux 等&#xff09;&#xff0c;选择对应的安装包进行下载。 2. 注册 cpolar 账号 步骤&#xff1a; 访问 cpolar…

Linux :进程状态

目录 1 引言 2 操作系统的资源分配 3进程状态 3.1运行状态 3.2 阻塞状态 3.3挂起状态 4.进程状态详解 4.1 运行状态R 4.2 休眠状态S 4.3深度睡眠状态D 4.4僵尸状态Z 5 孤儿进程 6 进程优先级 其他概念 1 引言 &#x1f33b;在前面的文章中&#xff0c;我们已…

openwebUI访问vllm加载deepseek微调过的本地大模型

文章目录 前言一、openwebui安装二、配置openwebui环境三、安装vllm四、启动vllm五、启动openwebui 前言 首先安装vllm&#xff0c;然后加载本地模型&#xff0c;会起一个端口好。 在安装openwebui,去访问这个端口号。下面具体步骤的演示。 一、openwebui安装 rootautodl-co…

DeepSeek-V3:AI语言模型的高效训练与推理之路

参考&#xff1a;【论文学习】DeepSeek-V3 全文翻译 在人工智能领域&#xff0c;语言模型的发展日新月异。从早期的简单模型到如今拥有数千亿参数的巨无霸模型&#xff0c;技术的进步令人瞩目。然而&#xff0c;随着模型规模的不断扩大&#xff0c;训练成本和推理效率成为了摆在…

Spring单例模式 Spring 中的单例 饿汉式加载 懒汉式加载

目录 核心特性 实现方式详解 1. 饿汉式&#xff08;Eager Initialization&#xff09; 2. 懒汉式&#xff08;Lazy Initialization&#xff09; 3. 静态内部类&#xff08;Bill Pugh 实现&#xff09; 4. 枚举&#xff08;Enum&#xff09; 破坏单例的场景及防御 Sprin…

DeepSeek MLA(Multi-Head Latent Attention)算法浅析

目录 前言1. 从MHA、MQA、GQA到MLA1.1 MHA1.2 瓶颈1.3 MQA1.4 GQA1.5 MLA1.5.1 Part 11.5.2 Part 21.5.3 Part 3 结语参考 前言 学习 DeepSeek 中的 MLA 模块&#xff0c;究极缝合怪&#xff0c;东抄抄西抄抄&#xff0c;主要 copy 自苏神的文章&#xff0c;仅供自己参考&#…

uniapp 中引入使用uView UI

文章目录 一、前言&#xff1a;选择 uView UI的原因二、完整引入步骤1. 安装 uView UI2. 配置全局样式变量&#xff08;关键&#xff01;&#xff09;3. 在 pages.json中添加&#xff1a;4. 全局注册组件5. 直接使用组件 五、自定义主题色&#xff08;秒换皮肤&#xff09; 一、…

zookeeper-docker版

Zookeeper-docker版 1 zookeeper概述 1.1 什么是zookeeper Zookeeper是一个分布式的、高性能的、开源的分布式系统的协调&#xff08;Coordination&#xff09;服务&#xff0c;它是一个为分布式应用提供一致性服务的软件。 1.2 zookeeper应用场景 zookeeper是一个经典的分…

【量化金融自学笔记】--开篇.基本术语及学习路径建议

在当今这个信息爆炸的时代&#xff0c;金融领域正经历着一场前所未有的变革。传统的金融分析方法逐渐被更加科学、精准的量化技术所取代。量化金融&#xff0c;这个曾经高不可攀的领域&#xff0c;如今正逐渐走进大众的视野。它将数学、统计学、计算机科学与金融学深度融合&…

unity学习56:旧版legacy和新版TMP文本输入框 InputField学习

目录 1 旧版文本输入框 legacy InputField 1.1 新建一个文本输入框 1.2 InputField 的子物体构成 1.3 input field的的component 1.4 input Field的属性 2 过渡 transition 3 控件导航 navigation 4 占位文本 placeholder 5 文本 text 5.1 文本内容&#xff0c;用户…

汽车电子电控软件开发中因复杂度提升导致的架构恶化问题

针对汽车电子电控软件开发中因复杂度提升导致的架构恶化问题&#xff0c;建议从以下方向进行架构优化和开发流程升级&#xff0c;以提升灵活性、可维护性和扩展性&#xff1a; 一、架构设计与模块化优化 分层架构与模块解耦 采用AUTOSAR标准的分层架构&#xff08;应用层、运行…

【弹性计算】弹性裸金属服务器和神龙虚拟化(一):功能特点

弹性裸金属服务器和神龙虚拟化&#xff08;一&#xff09;&#xff1a;功能特点 特征一&#xff1a;分钟级交付特征二&#xff1a;兼容 VPC、SLB、RDS 等云平台全业务特征三&#xff1a;兼容虚拟机镜像特征四&#xff1a;云盘启动和数据云盘动态热插拔特征五&#xff1a;虚拟机…

腾讯云大模型知识引擎驱动的DeepSeek满血版医疗顾问大模型搭建实战

文章目录 1. 引言2. 什么是腾讯云大模型知识引擎&#xff08;LKE&#xff09;&#xff1f;核心优势功能特点应用场景 3. 模型搭建过程3.1 注册登录产品3.2 创建应用3.3 配置模型3.4 配置角色指令3.5 配置欢迎语3.6 配置知识库3.7 配置工作流3.8 启用联网搜索3.9 发布模型 4. 问…

nio中ByteBuffer使用

创建ByteBuffer ByteBuffer buffer ByteBuffer.allocate(10);// 字符串转 bytebufferByteBuffer buffer01 Charset.defaultCharset().encode("hello world"); ByteBuffer buffer02 ByteBuffer.wrap("hello".getBytes()); ByteBuffer buffer03 Standard…

如何在 IntelliJ IDEA 中集成 DeepSeek

如何在 IntelliJ IDEA 中集成 DeepSeek 在本教程中&#xff0c;我们将带您一步步完成将 DeepSeek 集成到 IntelliJ IDEA 中的过程。通过此集成&#xff0c;您可以在IDE中利用DeepSeek强大的功能&#xff0c;提高开发工作效率。 步骤 1&#xff1a;安装 Proxy AI 插件 首先&a…

【Maven】入门介绍 与 安装、配置

文章目录 一、Maven简介1. Maven介绍2. Maven软件工作原理模型图 二、Maven安装和配置1. Maven安装2. Maven环境配置3. Maven功能配置4. IDEA配置本地Maven软件 一、Maven简介 1. Maven介绍 https://maven.apache.org/what-is-maven.html Maven 是一款为 Java 项目管理构建、…

Java数据结构第十六期:走进二叉树的奇妙世界(五)

专栏&#xff1a;Java数据结构秘籍 个人主页&#xff1a;手握风云 目录 一、非递归实现遍历二叉树 1.1. 二叉树的前序遍历 1.2. 二叉树的中序遍历 1.3. 二叉树的后序遍历 一、非递归实现遍历二叉树 1.1. 二叉树的前序遍历 我们这里要使用栈来进行实现。我们反向思考一下为…