多线程(七)线程池

简介: 多线程(七)线程池

线程池,又是一个池,我们已经见识过很多池了:


数据库连接池、字符串常量池....


那我们这个线程池又是个啥呢?


我们提前将线程准备好,需要用的时候直接取,不需要用的时候,在直接还回去。


这样就不需要去从系统中申请了。


这样做,最大的好处就是减少每次启动、销毁线程的损耗


池的目的就是为了提高效率。


为什么需要提高效率呢?


虽然线程对比于进程较为轻量,但是频繁的创建、销毁依旧开销很大。


为什么这也可以提升效率呢?


从线程池拿线程,时纯粹的用户态操作;

而从系统创建线程涉及到了用户态和内核态之间的切换;

真正的创建线程是要在内核态完成的。


举个栗子(🌰)


我们现在突然需要一个线程,我们直接可以从用户台中(前提是用户态中有线程);但是如果我们要从内核态中拿到这个线程,确实可以拿到,但是在拿的这个过程中内核还做了其他的很多事...


一旦涉及到了内核态时间就是不可控的。


用户态和内核态是操作系统中的基本概念:


内核态(Kernel Mode):运行操作系统程序,操作硬件


用户态(User Mode):运行用户程序


我们简单的理解:


一个操作系统  =  内核  +  配套的应用程序  


标准库中的线程池


我们先来写一个jdk 提供的线程池:


 public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(10);
        pool.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello");
            }
        });
    }


这里并不是使用 ThreadPool 而是使用 ExcutorService


bf06b971723b454e98dd788df917fcd3.png

工厂模式的概念:


000c74b85e344902821506df41c7f302.png


主要就是用来填构造方法的坑的。

这里的工厂模式主要来自于ThreadPoolExecutor 这个原装线程池对象,上述工厂类是对这个原生类进行了封装,只要了解清楚这个类,其他工厂类就简单了。

我们再来重点解释一下 这几个参数的含义:

c6af40537a9f40c4947dca56d28e0578.png

823d7ed6d3d04f119156679529d1d008.png


标准库中的四种拒绝策略:



拒绝策略类型 说明
1  ThreadPoolExecutor.AbortPolicy 默认拒绝策略,拒绝任务并抛出任务
2  ThreadPoolExecutor.DiscardPolicy  使用调用线程直接运行任务
3 ThreadPoolExecutor.DiscardOldestPolicy   直接拒绝任务,不抛出错误
4 ThreadPoolExecutor.CallerRunsPolicy  触发拒绝策略,只要还有任务新增,一直会丢弃阻塞队列的最老的任务,并将新的任务加入


接下来我们手动实现一个线程池:


实现线程池


看代码:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class MyThreadPool {
    private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
    // 作用类似于生产者,给线程添加任务
    public void submit(Runnable runnable) throws InterruptedException {
        queue.put(runnable);
    }
    // 此处实现一个固定线程数的线程池
    public MyThreadPool(int n) {
        // 循环内有一个工作线程
        // 类似于生产者,每次去取和执行这个任务
        for (int i = 0; i < n; i++) {
            //
            Thread t = new Thread(() -> {
                try {
                    while (true) {
                        Runnable runnable = queue.take();
                        runnable.run();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            t.start();
        }
    }
    public static void main(String[] args) throws InterruptedException {
        MyThreadPool pool = new MyThreadPool(10);
        for (int i = 0; i < 1000; i++) {
            int number = i;
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println("hello " + number);
                }
            });
        }
    }
}


我们来跑一跑:


73786b4f8c5c4708996a7c1ee7664893.png


因为线程的调度是无序的,虽然是 按顺序添加的,但是结果仍然是个无序的状态。


线程池的优点:


1. 降低资源的消耗,利用已创建的线程,降低了线程的不断地创建和销毁的资源浪费

2. 提高相应小笼包,每次都是直接使用已经创建好的线程,不必去等待线程的创建

3. 提高线程的可管理性: 线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,监控和调优。


多线程的基础也就到这结束了,这六章属于是面试常考,工作中常用的,我们接下来还有进阶部分,这属于锦上添花的,能记下来最好。

目录
打赏
0
0
0
0
2
分享
相关文章
|
5月前
|
【Java并发】【线程池】带你从0-1入门线程池
欢迎来到我的技术博客!我是一名热爱编程的开发者,梦想是编写高端CRUD应用。2025年我正在沉淀中,博客更新速度加快,期待与你一起成长。 线程池是一种复用线程资源的机制,通过预先创建一定数量的线程并管理其生命周期,避免频繁创建/销毁线程带来的性能开销。它解决了线程创建成本高、资源耗尽风险、响应速度慢和任务执行缺乏管理等问题。
301 60
【Java并发】【线程池】带你从0-1入门线程池
|
3月前
|
线程池是什么?线程池在实际工作中的应用
总的来说,线程池是一种有效的多线程处理方式,它可以提高系统的性能和稳定性。在实际工作中,我们需要根据任务的特性和系统的硬件能力来合理设置线程池的大小,以达到最佳的效果。
92 18
阿里面试:5000qps访问一个500ms的接口,如何设计线程池的核心线程数、最大线程数? 需要多少台机器?
本文由40岁老架构师尼恩撰写,针对一线互联网企业的高频面试题“如何确定系统的最佳线程数”进行系统化梳理。文章详细介绍了线程池设计的三个核心步骤:理论预估、压测验证和监控调整,并结合实际案例(5000qps、500ms响应时间、4核8G机器)给出具体参数设置建议。此外,还提供了《尼恩Java面试宝典PDF》等资源,帮助读者提升技术能力,顺利通过大厂面试。关注【技术自由圈】公众号,回复“领电子书”获取更多学习资料。
|
5月前
|
python3多线程中使用线程睡眠
本文详细介绍了Python3多线程编程中使用线程睡眠的基本方法和应用场景。通过 `time.sleep()`函数,可以使线程暂停执行一段指定的时间,从而控制线程的执行节奏。通过实际示例演示了如何在多线程中使用线程睡眠来实现计数器和下载器功能。希望本文能帮助您更好地理解和应用Python多线程编程,提高程序的并发能力和执行效率。
129 20
Unity多线程使用(线程池)
在C#中使用线程池需引用`System.Threading`。创建单个线程时,务必在Unity程序停止前关闭线程(如使用`Thread.Abort()`),否则可能导致崩溃。示例代码展示了如何创建和管理线程,确保在线程中执行任务并在主线程中处理结果。完整代码包括线程池队列、主线程检查及线程安全的操作队列管理,确保多线程操作的稳定性和安全性。
JAVA线程池监控以及动态调整线程池
【10月更文挑战第22天】在 Java 中,线程池的监控和动态调整是非常重要的,它可以帮助我们更好地管理系统资源,提高应用的性能和稳定性。
434 64
|
7月前
|
单线程传奇Redis,为何引入多线程?
Redis 4.0 引入多线程支持,主要用于后台对象删除、处理阻塞命令和网络 I/O 等操作,以提高并发性和性能。尽管如此,Redis 仍保留单线程执行模型处理客户端请求,确保高效性和简单性。多线程仅用于优化后台任务,如异步删除过期对象和分担读写操作,从而提升整体性能。
129 1
在 Java 中使用线程池监控以及动态调整线程池时需要注意什么?
【10月更文挑战第22天】在进行线程池的监控和动态调整时,要综合考虑多方面的因素,谨慎操作,以确保线程池能够高效、稳定地运行,满足业务的需求。
199 38
|
8月前
|
.如何根据 CPU 核心数设计线程池线程数量
IO 密集型:核心数*2 计算密集型: 核心数+1 为什么加 1?即使当计算密集型的线程偶尔由于缺失故障或者其他原因而暂停时,这个额外的线程也能确保 CPU 的时钟周期不会被浪费。
303 4
|
8月前
|
线程池内部机制:线程的保活与回收策略
【10月更文挑战第24天】 线程池是现代并发编程中管理线程资源的一种高效机制。它不仅能够复用线程,减少创建和销毁线程的开销,还能有效控制并发线程的数量,提高系统资源的利用率。本文将深入探讨线程池中线程的保活和回收机制,帮助你更好地理解和使用线程池。
367 2
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问