手写精简版的java线程池
一、谈谈池化技术
- 简单点来说,就是预先保存好大量的资源,这些是可复用的资源,你需要的时候给你。对于线程,内存,oracle的连接对象等等,这些都是资源,程序中当你创建一个线程或者在堆上申请一块内存时,都涉及到很多系统调用,也是非常消耗CPU的,如果你的程序需要很多类似的工作线程或者需要频繁的申请释放小块内存,如果没有在这方面进行优化,那很有可能这部分代码将会成为影响你整个程序性能的瓶颈。池化技术主要有线程池,内存池,连接池,对象池等等,对象池就是提前创建很多对象,将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用。
二、再来看看我们今天所要关注的线程池
-
线程池的作用:为了限制系统中执行线程的数量。
- 根据系统的自身配置、环境等情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池里的线程处于等待。当一个新任务需要运行时,如果线程池中有等待的工作线程(空闲的线程),就可以开始运行了;否则依旧在等待队列。
-
为什么要使用线程池
-
线程的创建/销毁伴随着系统开销,若是过于频繁的创建/销毁线程,会很大程度上影响处理效率;如果使用线程池就能达到每个工作线程都可以被重复利用,可执行多个任务。
- 可以根据自身系统的承受能力,调整线程池中线程的数目,防止因为消耗过多的内存。
- 对线程进行一些简单的管理;如定时开始,周期执行,并发数控制等等。
三、下面代码实现精简版的线程池
- 创建一个线程池接口第一一些基本的方法(模仿jdk里面写个线程池接口)ThreadPoolInterface.java
package com.zzq.core.pool;
/**
* zhouzhongqing
* 2018年5月6日13:53:35
* 接口
* */
public interface ThreadPoolInterface {
/**
* @param task
* @return
* 添加任务
*/
int addWork(Runnable task);
/**
* 停止全部线程执行任务
* @return int
*
*/
int stopAll();
}
- 实现类ThreadPoolInterfaceImpl.java
package com.zzq.core.pool;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadPoolInterfaceImpl implements ThreadPoolInterface {
//线程的个数 默认开启100个线程执行任务
private static volatile Integer workNum = 100;
//任务队列
private static LinkedBlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>();
static AtomicInteger count = new AtomicInteger(0);
WorkThread [] workThread;
public ThreadPoolInterfaceImpl() {
this(workNum);
}
public ThreadPoolInterfaceImpl(int workNum) {
if(0 != workNum) ThreadPoolInterfaceImpl.workNum= workNum;
workThread = new WorkThread[workNum];
//预先开启线程
for (int i = 0; i < workNum; i++) {
workThread[i] = new WorkThread();
Thread t = new Thread(workThread[i],"线程 - "+ i + ": name");
t.start();
System.out.println("线程: "+ i + ":已开启");
}
}
public int addWork(Runnable task) {
taskQueue.offer(task);
taskQueue.notifyAll();
return 1;
}
@Override
public int stopAll() {
//new WorkThread().setIsRuning();
if(null != workThread){
for(int i = 0;i <workThread.length ; i++){
workThread[i].setIsRuning();
}
return 1;
}
return 0;
}
public static void main(String[] args) {
new ThreadPoolInterfaceImpl();
}
static class WorkThread extends Thread{
volatile boolean isRuning = true;
@Override
public void run() {
//预先开好的线程去消费这个任务队列
while (true) {
if(isRuning){
if(isRuning && taskQueue.isEmpty()){
try {
taskQueue.wait(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("等待添加任务状态");
}else{
if(!taskQueue.isEmpty()){
//从任务队列中取出执行
Runnable r = taskQueue.poll();
if(null != r ) {
r.run();
System.out.println(" 当前执行第 [ "+count.incrementAndGet() +" ] 次任务" );
}
}
}
}
}
}
public void setIsRuning(){
this.isRuning = false;
}
}
}
- 测试类 Test.java
package com.zzq.core.pool;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.zzq.core.pool.ThreadPoolInterfaceImpl.WorkThread;
public class Test {
private static ExecutorService cachedThreadPool =Executors.newCachedThreadPool();
public static void main(String[] args) {
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println("当前执行任务的线程名称"+ Thread.currentThread() + "---------");
}
};
Long starTime = System.currentTimeMillis();
ThreadPoolInterface ti = (ThreadPoolInterfaceImpl)new ThreadPoolInterfaceImpl();
for (int i = 0; i < 111111110; i++) {
ti.addWork(run);
}
System.out.println();
}
}
- 运行结果
推荐看看java连接池实现,这两篇都是池化技术,可能更容易理解线程池和连接池的区别和相近之处等等。代码或者我理解上有问题的地方,还请不吝指正。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现