大家好 , 这篇文章给大家带来的是多线程当中的线程池 , 使用线程池可以降低资源消耗 , 通过重复利用已创建的线程降低线程创建和销毁造成的消耗 . 还可以提高响应速度 , 当任务到达时,任务可以不需要等到线程创建就能立即执行
我们会从三个角度分析线程池
- 线程池是什么
- 标准库中的线程池
- 我们自己实现一个线程池
推荐大家跳转到此链接查看文章体验效果更好嗷~
上一篇文章的链接我也给大家贴在这里了
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 方法给线程池添加任务 , 线程池内部再持有一些线程来消费执行这里的任务
线程池就相当于一个简单的生产者-消费者模型文章来源:https://www.toymoban.com/news/detail-405187.html
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");
}
});
}
}
}
到这里 , 多线程基础部分就已经结束了
如果对你有帮助的话 , 请一键三连嗷~
文章来源地址https://www.toymoban.com/news/detail-405187.html
到了这里,关于Java Web 实战 10 - 多线程基础之线程池的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!