JavaEE-线程进阶



模拟实现一个定时器








运行结果如下:

上述模拟定时器的全部代码:
import java.util.PriorityQueue;//创建一个类,用来描述定时器中的一个任务
class MyTimerTask implements Comparable<MyTimerTask> {//任务执行时间private long time;//具体任务private Runnable runnable;//构造函数public MyTimerTask(Runnable runnable,long delay) {this.time = System.currentTimeMillis()+delay;this.runnable = runnable;}public long getTime() {return time;}public Runnable getRunnable() {return runnable;}@Overridepublic int compareTo(MyTimerTask o) {//时间小的任务,会被放置在队首return (int)(this.time-o.time);}
}//定时器类的本体
class MyTimer{//创建一个优先级队列存储上述的N个任务private PriorityQueue<MyTimerTask> queue=new PriorityQueue<>();//用来加锁的对象private Object locker=new Object();//提供一个schedule方法,把要执行的任务添加到队列中去public void schedule(Runnable runnable,long delay){//new 一个任务对象synchronized (locker){MyTimerTask task=new MyTimerTask(runnable,delay);queue.offer(task);//每次来新的任务,都唤醒之前的扫描线程,让扫描线程根据当前的任务情况,重新规划等待时间locker.notify();}}//构造函数 提供一个扫描线程,一方面去监控队首元素是否到执行时间了,另一方面,如果到了执行时间,这需要调用这里的Runable中的run方法来完成任务public MyTimer(){Thread t=new Thread(() ->{while(true){try {synchronized (locker){while(queue.isEmpty()){//如果当前队列为空,就不应该去队列中取任务,使用wait进行等待,直到有任务加入队列locker.wait();}//判断当前队列中的队首元素距离执行时间的时间差MyTimerTask task=queue.peek();long curTime=System.currentTimeMillis();if(curTime>=task.getTime()){//当前时间大于等于任务的执行时间,开始执行queue.poll();//把已经执行的任务弹出队列task.getRunnable().run();//执行任务}else{//没有到任务时间,扫描线程休眠时间差//Thread.sleep(task.getTime()-curTime);locker.wait(task.getTime()-curTime);}}}catch (InterruptedException e) {e.printStackTrace();}}});t.start();}}public class Demo21 {public static void main(String[] args) {MyTimer timer=new MyTimer();timer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello 3");}},3000);timer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello 2");}},2000);timer.schedule(new Runnable() {@Overridepublic void run() {System.out.println("hello 1");}},1000);System.out.println("程序开始运行");}
}
线程池









模拟实现一个线程池
只需要提交任务给线程池即可
核心操作为 submit, 将任务加入线程池中
使用一个 BlockingQueue 组织所有的任务
代码如下:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;//模拟实现一个线程池
class MyThreadPool{//将添加到线程池中的任务可以放置到这个队列中private BlockingQueue<Runnable> queue =new LinkedBlockingQueue<>();//通过这个方法可以将任务添加到线程池中public void submit(Runnable runnable) throws InterruptedException {queue.put(runnable);}//构造函数,创建一个线程池,数量为npublic MyThreadPool(int n){for (int i = 0; i <n; i++) {Thread t=new Thread(() ->{while(true){try {//取放入线程池队列中的任务进行执行Runnable runnable= queue.take();runnable.run();} catch (InterruptedException e) {e.printStackTrace();}}});t.start();}}}
public class Demo23 {public static void main(String[] args) throws InterruptedException {MyThreadPool myThreadPool=new MyThreadPool(4);for (int i = 0; i <10; i++) {myThreadPool.submit(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"hello");}});}}
}
执行结果如下:


进阶内容










上述第二种情况的案例,如下

结果如下:

上述过程的所有代码:
//死锁
public class Demo24 {private static Object locker1=new Object();private static Object locker2=new Object();public static void main(String[] args) {Thread t1=new Thread(() ->{synchronized (locker1) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (locker2){System.out.println("t1 两把锁加锁成功");}}});Thread t2=new Thread(() ->{synchronized (locker2) {try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (locker1){System.out.println("t2 两把锁加锁成功");}}});t1.start();t2.start();}
}
我们可以通过jconsole来观察线程的执行过程











利用原子类实现线程安全

上述的代码如下:
import java.util.concurrent.atomic.AtomicInteger;//利用原子类实现线程安全
public class Demo25 {private static AtomicInteger count=new AtomicInteger(0);public static void main(String[] args) throws InterruptedException {Thread t1=new Thread(() -> {for (int i = 0; i <5000; i++) {count.getAndIncrement();//后置++}});Thread t2=new Thread(() -> {for (int i = 0; i <5000; i++) {count.getAndIncrement();//后置++}});t1.start();t2.start();t1.join();t2.join();System.out.println(count.get());}
}








下面利用Callable建立一个线程

上述过程的代码如下:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
//利用Callable建立一个线程
public class Demo26 {public static void main(String[] args) throws ExecutionException, InterruptedException {Callable<Integer> callable =new Callable<Integer>() {@Overridepublic Integer call() throws Exception {int sum=0;for (int i = 0; i <1000; i++) {sum+=i;}return sum;}};//callable不能直接用,需要借用FutureTask这个标签FutureTask<Integer> futureTask=new FutureTask<>(callable);Thread t =new Thread(futureTask);t.start();System.out.println(futureTask.get());}
}






下面简单使用一下这个信号量

上述过程的完整代码如下:
import java.util.concurrent.Semaphore;
//Semaphore 信号量
public class Demo27 {public static void main(String[] args) throws InterruptedException {//指定计数器的初始值Semaphore semaphore=new Semaphore(4);semaphore.acquire();System.out.println("执行了一次P操作");semaphore.acquire();System.out.println("执行了一次P操作");semaphore.acquire();System.out.println("执行了一次P操作");semaphore.acquire();System.out.println("执行了一次P操作");semaphore.acquire();System.out.println("执行了一次P操作");}
}
同时等待 N 个任务执行结束.

上述过程的完整代码如下:
import java.util.concurrent.CountDownLatch;
//使用CountDownLatch将任务分配给多个线程来完成
public class Demo28 {public static void main(String[] args) throws InterruptedException {//指定创建任务的数量CountDownLatch countDownLatch=new CountDownLatch(10);for (int i = 0; i <10; i++) {int id=i;Thread t=new Thread(() ->{System.out.println( id + "开始工作");try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println( id + "结束工作");// 每个任务执行结束这里, 调用一下方法,记录该线程是否结束// 把 10 个线程想象成短跑比赛的 10 个运动员. countDown 就是运动员撞线了.countDownLatch.countDown();});t.start();}// 主线程中可以使用 countDownLatch 负责等待任务结束.// a => all 等待所有任务结束. 当调用 countDown 次数 < 初始设置的次数, await 就会阻塞.countDownLatch.await();System.out.println("所有任务执行完毕");}
}








相关文章:
JavaEE-线程进阶
模拟实现一个定时器 运行结果如下: 上述模拟定时器的全部代码: import java.util.PriorityQueue;//创建一个类,用来描述定时器中的一个任务 class MyTimerTask implements Comparable<MyTimerTask> {//任务执行时间private long …...
【开发篇】十五、Spring Task实现定时任务
文章目录 1、使用示例2、相关配置3、Scheduled注解4、Spring Task单线程下的阻塞坑5、Spring Task阻塞问题的处理思路6、Spring Task在分布式环境中 上一篇用Quartz来实现了定时任务,但相对来说,这个框架还是比较繁琐。Spring Boot默认在无任何第三方依赖…...
Python常用功能的标准代码
后台运行并保存log 1 2 3 4 5 6 7 8 9 nohup python -u test.py > test.log 2>&1 & #最后的&表示后台运行 #2 输出错误信息到提示符窗口 #1 表示输出信息到提示符窗口, 1前面的&注意添加, 否则还会创建一个名为1的文件 #最后会把日志文件输出到test.log文…...
Electron.js入门-构建第一个聊天应用程序
什么是electron 电子是一个开源框架,用于使用web技术构建跨平台桌面应用程序;即: HTML、CSS和JavaScript;被集成为节点模块,我们可以为我们的应用程序使用节点的所有功能;组件,如数据库、Api休…...
ubuntu 22.04 更新NVIDIA显卡驱动,重启后无网络图标等系统奇奇怪怪问题
环境 win10, ubuntu 22.04双系统 笔记本电脑,4060显卡 解决思路 具体的过程当时没有记录下来,然后因为在解决系统的问题,也没有截图啥的,只有一些大概记忆,供未来的自己参考吧。 首先是更新显卡驱动 我是直接在soft…...
Python综合案例:学生管理系统
目录 需求说明: 功能: 创建入口函数: 实现菜单函数: 实现增删查操作: 1. 新增学生 2. 展示学生 3. 查找学生 4. 删除学生 加入存档读档: 1. 约定存档格式 2. 实现存档函数 3. 实现读档函数 打…...
IDT 一款自动化挖掘未授权访问漏洞的信息收集工具
IDT v1.0 IDT 意为 Interface detection(接口探测) 项目地址: https://github.com/cikeroot/IDT/该工具主要的功能是对批量url或者接口进行存活探测,支持浏览器自动打开指定的url,避免手动重复打开网址。只需输入存在批量的url文件即可。 …...
复习 --- 消息队列
进程间通信机制(IPC) 简述 IPC:Inter Process Communication 进程和进程之间的用户空间相互独立,但是4G内核空间共享,进程间的通信就是通过这4G的内核空间 分类 传统的进程间通信机制 无名管道(pipe) 有名管道&…...
AcWing 288. 休息时间,《算法竞赛进阶指南》
288. 休息时间 - AcWing题库 在某个星球上,一天由 N 个小时构成,我们称 0 点到 1 点为第 1 个小时、1 点到 2 点为第 2 个小时,以此类推。 在第 i 个小时睡觉能够恢复 Ui 点体力。 在这个星球上住着一头牛,它每天要休息 B 个小…...
ES6中字符串的扩展
字符串的遍历器接口 使用for…of for(let x of foo) {console.log(x); } // f; o; oat() ES5中的charAt()方法,返回字符串给定位置的字符。但是不能识别码点大于0xFFFF的字符,at方法可以 includes()、startsWith()、endsWith() 用来确定一个字符串是…...
GEO生信数据挖掘(四)数据清洗(离群值处理、低表达基因、归一化、log2处理)
检索到目标数据集后,开始数据挖掘,本文以阿尔兹海默症数据集GSE1297为例 目录 离群值处理 删除 低表达基因 函数归一化,矫正差异 数据标准化—log2处理 完整代码 上节围绕着探针ID和基因名称做了一些清洗工作,还做了重复值检查…...
CI/CD工具中的CI和CD的含义
CI/CD工具中的CI和CD的含义? CI/CD 是现代软件开发方法中广泛使用的一种方法。其中,CI 代表持续集成(Continuous Integration),CD 则有两层含义,一是持续交付(Continuous Delivery)…...
用go获取IPv4地址,WLAN的IPv4地址,本机公网IP地址详解
文章目录 获取IPv4地址获取WLAN的IPv4地址获取本机公网IP地址 获取IPv4地址 下面的代码会打印出本机所有的IPv4地址。这个方法可能会返回多个IP地址,因为一台机器可能有多个网络接口,每个接口可能有一个或多个IP地址。 package mainimport ("fmt&…...
Android自定义Drawable---灵活多变的矩形背景
Android自定义Drawable—灵活多变的矩形背景 在安卓开发中,我们通常需要为不同的按钮设置不同的背景以实现不同的效果,有时还需要这些按钮根据实际情况进行变化。如果采用编写resource中xml文件的形式,就需要重复定义许多只有微小变动的资源…...
ParagonNTFSforMac_15.5.102中文版最受欢迎的NTFS硬盘格式读取工具
Paragon NTFS for Mac是一款可以为您轻松解决Mac平台上不能识别Windows通用的NTFS文件难题,这是一款强大的Mac读写工具,相信在很多时候,Mac用户需要对NTFS文件的移动硬盘进行写入,但是macOS系统默认是不让写入的,使用小…...
Kafka 搭建过程
目录 1.关于Kafka2.Kafka 搭建过程3.参考 本文主要介绍Kafka基本原理,以及搭建过程。 1.关于Kafka Apache Kafka是一个开源的分布式事件流平台,被设计用来实现实时数据流的发布、订阅、存储和处理。 Kafka的主要特性包括: 高吞吐量&#x…...
七、2023.10.1.Linux(一).7
文章目录 1、 Linux中查看进程运行状态的指令、查看内存使用情况的指令、tar解压文件的参数。2、文件权限怎么修改?3、说说常用的Linux命令?4、说说如何以root权限运行某个程序?5、 说说软链接和硬链接的区别?6、说说静态库和动态…...
一文教你搞懂Redis集群
一、Redis主从 1.1、搭建主从架构 单节点的Redis的并发能力是有上限的,要进一步的提高Redis的并发能力,据需要大家主从集群,实现读写分离。 共包含三个实例,由于资源有限,所以在一台虚拟机上,开启多个red…...
树上启发式合并 待补
对于每个子树,直接遍历所有轻儿子,继承重儿子 会了板子后,修改维护的东西和莫队是一样的 洛谷 U41492 #include <bits/stdc.h> #define ll long long #define ull unsigned long long constexpr int N1e55; std::vector<int> e…...
minio分布式文件存储
基本介绍 什么是 MinIO MinIO 是一款基于 Go 语言的高性能、可扩展、云原生支持、操作简单、开源的分布式对象存储产品。基于 Apache License v2.0 开源协议,虽然轻量,却拥有着不错的性能。它兼容亚马逊S3云存储服务接口。可以很简单的和其他应…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...
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 …...
