【Java多线程】对线程池的理解并模拟实现线程池

简介: 【Java多线程】对线程池的理解并模拟实现线程池

1、池

“池”这个概念见到非常多,例如常量池、数据库连接池、线程池、进程池、内存池。


所谓“池”的概念就是:(提高效率)

1、提前把要用的对象准备好

2、用完的对象也不立即释放,留着以备下次使用。

从而大大降低了线程频繁地创建销毁造成的开销。


1.1、线程池

线程池也是如此,提前把要使用的线程,在线程池中准备好,等到需要用时就从池子里取


出,用完之后再归还给池子。


(其中取出和归还操作都是属于纯用户态代码,这就比内核操作更快,更可控)


上面提到了用户态,什么是用户态呢?


       设想一个场景,你在银行柜台办理业务,该业务需要用到身份证复印件,此时有两种选择:一种是柜员拿着你的身份证帮你去复印,一种是你自己去复印。


       显然自己去复印这个操作更加可靠,并且可控一些。如果交给柜员去复印,天知道柜员拿了你的身份证后还去做了什么,因为柜员本身需要处理的事情不止有帮你复印身份证这一件事,可能在帮你复印身份证的路上去做了别的事情,你能做的就只有在柜台前等柜员回来,这种操作显然更加不可控。


你自己去操作就相当于用户态,而柜员帮你操作就相当于是内核态。


而类比到计算机上简单来说就是:


如果一个任务,是在用户程序上完成的,就属于用户态,此时更加的可控。


如果一个任务,是通过系统申请创建线程,需要由内核来完成,就属于内核态,此时更加不可控。


2、ThreadPoolExecutor 线程池类

Java 在标准库中提供了 ThreadPoolExecutor 线程池类



  • corePoolSize:核心线程数
  • maximumPoolSize:最大线程数
  • keepAliveTime:空闲时保持存活的时间(针对临时线程的)
  • unit:存活时间的时间单位(s,min,ms,hour....)
  • workQueue:阻塞队列,和定时器类似,线程池中也可以持有很多个任务
  • threadFactory:线程工厂(这个类中的方法封装了 new Thread 的操作,同时给 Thread 设置了一些属性)
  • handler:拒绝策略,当线程池中的阻塞队列满时,继续往队列中添加任务,此时线程池会执行什么样的操作就称为拒绝策略

针对拒绝策略,又分为四种:


1、继续添加任务直接拒绝接收并报错。【直接报错,新旧任务都不干了】


2、新的任务,由添加任务的线程负责执行。【谁揽的活儿谁干】


3、丢弃最旧的任务,新的添加进来。


4、丢弃新来的任务。



3、Executors 工厂类

ThreadPoolExecutor 本身用起来比较复杂,因此标准库还把 ThreadPoolExecutor 封装了一层,提供了另一个版本。


即 Executors 工厂类,通过这个类来创建出不同的线程池对象。


Executors 创建线程池的几种方式:


  • newFixedThreadPool: 创建固定线程数的线程池
  • newCachedThreadPool: 创建线程数目动态增长的线程池.
  • newSingleThreadExecutor: 创建只包含单个线程的线程池.
  • newScheduledThreadPool: 设定 延迟时间后执行命令,或者定期执行命令. 是进阶版的 Timer.
public class ExecutorDemo {
    public static void main(String[] args) {
        //将线程数设置为 10
        ExecutorService service = Executors.newFixedThreadPool(10);
        //使用 submit 方法向线程池中提交任务
        service.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello Executors");
            }
        });
    }
}

既然 ThreadPoolExecutor 和 Executors 都可以创建线程池,那么到底该用哪个呢?


正常情况下直接使用 Executors 工厂类即可,当 Executors 工厂类提供的方法无法满足使用时,或者是想要高度定制化线程池时,才去使用 ThreadPoolExecutor。


4、模拟实现线程池

这里模拟写一个固定线程数目的线程池,即模拟使用 newFixedThreadPool 创建的线程池。


分析要点:


1、首先需要提供构造方法,方法中指定创建多少个线程


2、在构造方法中,把这些线程都创建好


3、用一个阻塞队列,将要执行的任务保存起来


4、提供 submit 方法,用于添加新的任务到阻塞队列中


public class MyThreadPoolExecutor {
    // 保存线程的集合
    private List<Thread> threadList = new ArrayList<>();
    // 保存任务的阻塞队列
    private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);
    public MyThreadPoolExecutor(int n) {  //创建n个线程
        for (int i = 0; i < n; i++) {
            Thread t = new Thread(() -> {
                //这些线程需要做的就是不断从任务队列中取出任务并执行
                while (true) {
                    try {
                        // take 带有阻塞功能,为空时自动阻塞
                        Runnable runnable = queue.take();
                        runnable.run();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
            //启动线程
            t.start();
            //将线程存入集合中,以备后续使用
            threadList.add(t);
        }
    }
    //submit 添加新的任务到队列中
    public void submit(Runnable runnable) throws InterruptedException {
        queue.put(runnable);
    }
}


目录
相关文章
|
7天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
37 6
|
16天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
16天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
40 3
|
17天前
|
监控 Java 开发者
深入理解Java中的线程池实现原理及其性能优化####
本文旨在揭示Java中线程池的核心工作机制,通过剖析其背后的设计思想与实现细节,为读者提供一份详尽的线程池性能优化指南。不同于传统的技术教程,本文将采用一种互动式探索的方式,带领大家从理论到实践,逐步揭开线程池高效管理线程资源的奥秘。无论你是Java并发编程的初学者,还是寻求性能调优技巧的资深开发者,都能在本文中找到有价值的内容。 ####
|
20天前
|
监控 Java 数据库连接
Java线程管理:守护线程与用户线程的区分与应用
在Java多线程编程中,线程可以分为守护线程(Daemon Thread)和用户线程(User Thread)。这两种线程在行为和用途上有着明显的区别,了解它们的差异对于编写高效、稳定的并发程序至关重要。
28 2
|
20天前
|
监控 Java 开发者
Java线程管理:守护线程与本地线程的深入剖析
在Java编程语言中,线程是程序执行的最小单元,它们可以并行执行以提高程序的效率和响应性。Java提供了两种特殊的线程类型:守护线程和本地线程。本文将深入探讨这两种线程的区别,并探讨它们在实际开发中的应用。
27 1
|
4月前
|
存储 监控 Java
Java多线程优化:提高线程池性能的技巧与实践
Java多线程优化:提高线程池性能的技巧与实践
130 1
|
7月前
|
设计模式 监控 Java
Java多线程基础-11:工厂模式及代码案例之线程池(一)
本文介绍了Java并发框架中的线程池工具,特别是`java.util.concurrent`包中的`Executors`和`ThreadPoolExecutor`类。线程池通过预先创建并管理一组线程,可以提高多线程任务的效率和响应速度,减少线程创建和销毁的开销。
236 2
|
4月前
|
安全 算法 Java
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)(下)
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)
84 6
|
4月前
|
存储 安全 Java
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)(中)
17 Java多线程(线程创建+线程状态+线程安全+死锁+线程池+Lock接口+线程安全集合)
91 5
下一篇
DataWorks