Java Web 实战 10 - 多线程基础之线程池
大家好 , 这篇文章给大家带来的是多线程当中的线程池 , 使用线程池可以降低资源消耗 , 通过重复利用已创建的线程降低线程创建和销毁造成的消耗 . 还可以提高响应速度 , 当任务到达时,任务可以不需要等到线程创建就能立即执行
我们会从三个角度分析线程池
- 线程池是什么
- 标准库中的线程池
- 我们自己实现一个线程池
8.4 线程池
对于 “池” 这个字 , 我们学习过 : “字符串常量池” “数据库连接池” “备胎池”
“备胎池” : 养了许多的备胎 , 这个分了那个就无缝连接 , 提高了效率
进程已经能做到并发编程了 , 为什么还需要线程 ?
进程实在是太重量了 , 创建和销毁成本都比较高 , 需要申请释放资源
线程就是针对上述问题的优化 , 因为他是共用同一组系统资源的 , 一旦资源申请好了 , 后续就不需要再继续申请了
虽然线程已经很好了 , 不过在更高频率下的创建释放的情况下 , 线程也就扛不住了
所以还需要进一步优化 :
- 线程池
- 协程 (也叫做纤程) , 更加轻量级的线程
我们主要研究一下线程池 :
线程池解决的思路就是把线程创建好之后 , 放到池子中 , 而不是通过系统来销毁
当线程用完了 , 还是还回到池子中 , 而不是通过系统来进行销毁
上述操作 , 就又进一步的提高效率了
❗ 那为什么把线程放到池子里 , 然后从池子中取出线程就要比从系统中创建线程来得快呢 ?
✅ 从池子中取 , 是纯用户态操作 . 通过系统来创建 , 涉及到内核态操作
通常认为 , 牵扯到内核态的操作1 , 就是要比纯用户态的操作更低效
为什么说用户态操作比内核态操作更高效呢 ?
举个栗子 :
1. 标准库中的线程池
刚才是创建的固定个数的线程池
我们还可以创建线程数量动态增加的线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo24 {
public static void main(String[] args) {
// ExecutorService 叫做执行器服务
// Executors.newFixedThreadPool() 创建固定线程个数的线程池
// Executors 是静态方法
// Executors通过.的方式调用静态方法
// 固定个数的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(10);
// 线程数量动态增加的线程池
// Executors.newCachedThreadPool();
}
}
学习完怎样创建之后 , 我们接下来就可以使用线程池了
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Demo24 {
public static void main(String[] args) {
// ExecutorService 叫做执行器服务
// Executors.newFixedThreadPool() 创建固定线程个数的线程池
// Executors 是静态方法
// Executors 通过.的方式调用静态方法
// 固定个数的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(10);
// 线程数量动态增加的线程池
// Executors.newCachedThreadPool();
// 把任务加入到线程池中
// 与定时器类似,线程池内部也有线程阻止退出,我们需要手动关闭
threadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println("hello 线程池");
}
});
}
}
2. 自己实现简单的线程池
阻塞队列来保存一些任务 , submit 方法给线程池添加任务 , 线程池内部再持有一些线程来消费执行这里的任务
线程池就相当于一个简单的生产者-消费者模型
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
class MyThreadPool {
// 由于插入任务可以一次性插入很多.需要能够把当前尚未执行的任务都保存起来 -> 队列
// 这个队列就是一个任务队列,把当前线程池中要完成的内容都放到这个队列里
// 再由线程池内部的工作线程负责完成他们
private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
// 核心方法:往线程池中插入任务
public void submit(Runnable runnable) {
try {
queue.put(runnable);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 构造方法中,就需要创建一些线程,让这些线程负责完成上述执行任务的工作
public MyThreadPool(int n) {
for (int i = 0; i < n; i++) {
Thread t = new Thread(() -> {
// 直接写成 true 就写死了,也别让他一直循环
// 我们可以改成 !Thread.currentThread().isInterrupted()
// 作用
// 1. 判断标志位
// 2. 处理异常
while(!Thread.currentThread().isInterrupted()) {
try {
Runnable runnable = queue.take();
runnable.run();
} catch (InterruptedException e) {
e.printStackTrace();
break;// 直接处理
}
}
});
t.start();
}
}
}
public class Demo25 {
public static void main(String[] args) {
MyThreadPool myThreadPool = new MyThreadPool(10);
for (int i = 0; i < 100; i++) {
myThreadPool.submit(new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
});
}
}
}
到这里 , 多线程基础部分就已经结束了
如果对你有帮助的话 , 请一键三连嗷~
相关文章
- 【技术种草】cdn+轻量服务器+hugo=让博客“云原生”一下
- CLB运维&运营最佳实践 ---访问日志大洞察
- vnc方式登陆服务器
- 轻松学排序算法:眼睛直观感受几种常用排序算法
- 十二个经典的大数据项目
- 为什么使用 CDN 内容分发网络?
- 大数据——大数据默认端口号列表
- Weld 1.1.5.Final,JSR-299 的框架
- JavaFX 2012:彻底开源
- 提升as3程序性能的十大要点
- 通过凸面几何学进行独立于边际的在线多类学习
- 利用行动影响的规律性和部分已知的模型进行离线强化学习
- ModelLight:基于模型的交通信号控制的元强化学习
- 浅谈Visual Source Safe项目分支
- 基于先验知识的递归卡尔曼滤波的代理人联合状态和输入估计
- 结合网络结构和非线性恢复来提高声誉评估的性能
- 最佳实践丨云开发CloudBase多环境管理实践
- TimeVAE:用于生成多变量时间序列的变异自动编码器
- 具有线性阈值激活的神经网络:结构和算法
- 内网渗透之横向移动 -- 从域外向域内进行密码喷洒攻击