【多线程】线程池总结带你详细了解线程池

简介: 【多线程】线程池总结带你详细了解线程池

线程池

线程池是一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。线程池最大的好处是减少了每次创建销毁线程的开销。

标准库中的线程池

Executors 创建线程池的几种方式

① 使用 Executors.newFixedThreadPool(5) 能创建出固定包含 5个线程的线程池

返回值类型为 ExecutorService

通过 ExecutorService.submit 可以注册一个任务到线程池中

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool01 {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 20; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
    }
}

② 使用 Executors.newCachedThreadPool()创建出的线程池对象的特点是线程池数目能够动态适应,随着往线程池里添加任务,这个线程池里的线程数量会根据需要自动被创建,创建之后也不会着急销毁,会在线程池里存在一段时间以备随时使用。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool2 {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newCachedThreadPool();
        for (int i = 0; i < 20; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
    }
}

③使用 Executors.newSingleThreadExecutor(): 创建只包含单个线程的线程池(一般用的不多)

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool3 {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 20; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
    }
}

④使用 Executors.newScheduledThreadPool():相当于是定时器 设定 延迟时间后执行命令,或者定期执行命令

import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class TheadPool4 {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newScheduledThreadPool(5);
        for (int i = 0; i < 20; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
    }
}

Executors 本质上是 ThreadPoolExecutor 类的封装,ThreadPoolExecutor 提供了更多的可选参数, 可以进一步细化线程池行为的设定。

ThreadPoolExecutor创建线程池

最后一个构造方法可以涵盖上面其他三个,所以我们重点来看最后一个构造方法。

参数详解:

corePoolSize:核心线程数------>我们如果把线程池理解成一个公司,核心线程数就相当于正式员工数量

maximumPoolSize:最大线程数------>正式员工 + 实习生

keepAliveTime:空余线程等待新任务的最大时间------>允许实习生摸鱼的最大时间(如果说正式员工可以摸鱼并且不会被开除,实习生不允许摸鱼)

unit:keepAliveTime的时间单位

workQueue:阻塞队列,用来存放线程池中的任务,可以根据需要来设置这里的队列是啥比如:如果需要优先级则可以设置为PriorityBlockingQueue 如果不需要优先级线程数目是恒定的则可以使用ArrayBlockingQueue 如果任务变动较大可以使用LinkedBlockingQueue

threadFactory:工厂模式的体现,这里使用threadFactory作为工厂类,由这个类负责创建线程,使用工厂类创建线程主要是为了在创建过程中可以很方便对线程的属性进行设置

handler:线程池的拒绝策略,一个线程池能够容纳的任务数量有上限,当持续向线程池中添加任务,一旦达到上限,不同的拒绝策略有不同的效果

拒绝策略:↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

问题讨论:使用线程池,设置多少线程数目合适呢???

解释:一个线程执行的代码主要有两类:①CPU密集型:代码主要是进行算数运算/逻辑判断 ②IO密集型:代码主要进行的是IO操作

假设一个线程的所有代码都是CPU密集型代码,这时线程池数量不应该超过N(CPU逻辑核心数),即使超过N也无法提高效率,CPU占满了增加线程反而会增加调度的开销。

假设一个线程的所有代码都是IO密集型,这时不占CPU,此时设置线程数就可以超过N,一个核心可以通过调度来并发执行。

但是纯CPU密集型和纯IO密集型代码一般工作中不会出现,所以线程池的线程数量应该对程序进行测试。

模拟实现线程池

模拟实现线程池我们需要知道线程池里有什么:

1、线程池管理器(ThreadPoolManager):用于创建并管理线程池

2、工作线程(WorkThread): 线程池中线程

3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行

4、任务队列:用于存放没有处理的任务。提供一种缓冲机制

核心操作为 submit, 将任务加入线程池中,使用一个 BlockingQueue 组织所有的任务 。

模拟实现一个简单版的线程池👇👇👇

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
//模拟实现线程池
public class MyThreadPool {
    //定义一个任务队列
    private BlockingQueue<Runnable> deque = new ArrayBlockingQueue<>(1000);
    //把任务添加到队列中
    public void submit(Runnable runnable) throws InterruptedException {
        deque.put(runnable);
    }
    public MyThreadPool(int n) {
        //创建出n个线程负责上述队列中的任务
        for (int i = 0; i < n; i++) {
            Thread t = new Thread(() -> {
                //让线程消费任务并执行
                try {
                    Runnable runnable = deque.take();
                    runnable.run();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            });
            t.start();
        }
    }
}
相关文章
|
6天前
|
存储 缓存 Java
什么是线程池?从底层源码入手,深度解析线程池的工作原理
本文从底层源码入手,深度解析ThreadPoolExecutor底层源码,包括其核心字段、内部类和重要方法,另外对Executors工具类下的四种自带线程池源码进行解释。 阅读本文后,可以对线程池的工作原理、七大参数、生命周期、拒绝策略等内容拥有更深入的认识。
什么是线程池?从底层源码入手,深度解析线程池的工作原理
|
7天前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android多线程编程的重要性及其实现方法,涵盖了基本概念、常见线程类型(如主线程、工作线程)以及多种多线程实现方式(如`Thread`、`HandlerThread`、`Executors`、Kotlin协程等)。通过合理的多线程管理,可大幅提升应用性能和用户体验。
25 15
一个Android App最少有几个线程?实现多线程的方式有哪些?
|
9天前
|
Java 数据库 Android开发
一个Android App最少有几个线程?实现多线程的方式有哪些?
本文介绍了Android应用开发中的多线程编程,涵盖基本概念、常见实现方式及最佳实践。主要内容包括主线程与工作线程的作用、多线程的多种实现方法(如 `Thread`、`HandlerThread`、`Executors` 和 Kotlin 协程),以及如何避免内存泄漏和合理使用线程池。通过有效的多线程管理,可以显著提升应用性能和用户体验。
29 10
|
16天前
|
存储 Ubuntu Linux
C语言 多线程编程(1) 初识线程和条件变量
本文档详细介绍了多线程的概念、相关命令及线程的操作方法。首先解释了线程的定义及其与进程的关系,接着对比了线程与进程的区别。随后介绍了如何在 Linux 系统中使用 `pidstat`、`top` 和 `ps` 命令查看线程信息。文档还探讨了多进程和多线程模式各自的优缺点及适用场景,并详细讲解了如何使用 POSIX 线程库创建、退出、等待和取消线程。此外,还介绍了线程分离的概念和方法,并提供了多个示例代码帮助理解。最后,深入探讨了线程间的通讯机制、互斥锁和条件变量的使用,通过具体示例展示了如何实现生产者与消费者的同步模型。
|
17天前
|
监控 Java
线程池中线程异常后:销毁还是复用?技术深度剖析
在并发编程中,线程池作为一种高效利用系统资源的工具,被广泛用于处理大量并发任务。然而,当线程池中的线程在执行任务时遇到异常,如何妥善处理这些异常线程成为了一个值得深入探讨的话题。本文将围绕“线程池中线程异常后:销毁还是复用?”这一主题,分享一些实践经验和理论思考。
31 3
|
23天前
|
数据采集 Java Python
python 递归锁、信号量、事件、线程队列、进程池和线程池、回调函数、定时器
python 递归锁、信号量、事件、线程队列、进程池和线程池、回调函数、定时器
|
24天前
|
Java
线程池中线程抛了异常,该如何处理?
【8月更文挑战第27天】在Java多线程编程中,线程池(ThreadPool)是一种常用的并发处理工具,它能够有效地管理线程的生命周期,提高资源利用率,并简化并发编程的复杂性。然而,当线程池中的线程在执行任务时抛出异常,如果不妥善处理,这些异常可能会导致程序出现未预料的行为,甚至崩溃。因此,了解并掌握线程池异常处理机制至关重要。
102 0
|
24天前
|
存储 监控 Java
Java多线程优化:提高线程池性能的技巧与实践
Java多线程优化:提高线程池性能的技巧与实践
48 1
|
24天前
|
监控 安全 Java
Java多线程调试技巧:如何定位和解决线程安全问题
Java多线程调试技巧:如何定位和解决线程安全问题
71 2