Java多线程-ThreadPool线程池-1(三)

java,多线程,threadpool,线程 · 浏览次数 : 51

小编点评

**线程池技术** **工作原理** 线程池是一种线程运行机制,它通过创建多个线程来提高系统性能。当需要处理的任务数量超过系统核心数时,可以创建一个新的线程来处理这些任务。线程池维护一个队列,将请求添加到线程池中。当有任务请求时,从队列中取出一个任务并将其分配给线程池中的线程。线程池会根据任务的优先级和等待时间为线程分配任务。 **优点** * 提高系统性能 * 减少等待时间 * 降低 CPU 使用率 **应用场景** 线程池适用于以下应用场景: * 单个任务处理时间较短 * 需要处理的任务数量大 * 必须对性能进行优化 **线程池状态** 线程池状态包括: * RUNNING:正常运行,接收新任务,处理阻塞队列中的任务。 * SHUTDOWN:关闭状态,不接收新任务,但可以继续处理阻塞队列中已有任务。 * STOP:既不接收新任务,也不处理队列中的任务,并会中断正在处理的任务。 * TIDYING:如果所有任务都已中止,且workCount有效线程数为0,则会调用terminated()方法进入TERMINATED状态。 * TERMINATED:terminated()方法执行完后进入该状态,什么也不做。

正文

开完一趟车完整的过程是启动、行驶和停车,但老司机都知道,真正费油的不是行驶,而是长时间的怠速、频繁地踩刹车等动作。因为在速度切换的过程中,发送机要多做一些工作,当然就要多费一些油。

而一个Java线程完整的生命周期就包括:

1、T1:创建(启动)

2、T2:运行(行驶)

3、T3:销毁(停车)

而T1 + T3的开销(汽油或者时间)是要远大于T2的。所以,即使是性能再好的车,或者性能再好的计算机,如果经常有T1 + T3的操作存在,那么显然是扛不住的。

所以,为了解决这种因为切换不同线程导致的效率问题,Java推出了线程池技术。通过对已创建线程的合理重用,既能解决上述问题,又能进一步提高响应速度,提升系统性能和稳定性。线程池特别适合下面的应用场景:

1、单个任务处理时间较短

2、需要处理的任务数量大

比如硬件数据采集,像手机、车载和安防传感器的数据采集就特别符合这种情况。

这是线程池相关继承结构图:

很多人都分不清Executor和Executors这两个东西:Executor是接口,是一个根据一组执行策略调用、调度、执行和控制的异步任务框架,提供了一种将“任务提交”与“任务如何运行”分离开的机制。而Executors则是一个工具类(不用new),提供了诸多用于线程池的静态方法。Executor和Executors的关系,和Java I/O中Collection和Collections的关系一毛一样。所以下次再看到XXX和XXXs的时候应该就知道Java的调性了。

说起来还是有点枯燥,那么我拿之前做的一个例子来说一下就明白了。

假设有一个工地有若干项目经理和工人,1个经理+1个工人组成工作小队,工地有很多个这样的工作小队,这些工作小队需要加入项目组,但是只有有活干的才能加入,没活干的加不了,就能要被优化裁员。

/**
 * 工人
 */
public class Worker {
    /**
     * 干活
     */
    public void dosomething() {
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("挖坑");
    }
}
/**
 * 经理
 */
public class Manager implements Runnable {
    private Worker worker;

    public Worker getWorker() {
        return worker;
    }

    public void setWorker(Worker worker) {
        this.worker = worker;
    }

    /**
     * 经理动嘴,工人动手
     */
    @Override
    public void run() {
        worker.dosomething();
    }
}
/**
 * 项目组
 */
public class ManagerGroup {
    private static ExecutorService projectGroup = new ThreadPoolExecutor(
            3, // 核心小队数量
            3, // 最多能容纳多少个小队
            30, // 多久没活干就请出项目组
            TimeUnit.SECONDS, // 时间单位
            new ArrayBlockingQueue<Runnable>(3),// 有多少个项目经理就不再接收入组申请
            new ThreadPoolExecutor.CallerRunsPolicy() // 项目组拒绝响应时怎么处理
    );

    // 项目组增加工作小队
    public static void addTask(Manager manager) {
        projectGroup.execute(manager);
    }

    public static void main(String[] args) {
        Manager manager1 = new Manager();
        Worker worker1 = new Worker();
        manager1.setWorker(worker1);

        Manager manager2 = new Manager();
        Worker worker2 = new Worker();
        manager2.setWorker(worker2);

        Manager manager3 = new Manager();
        Worker worker3 = new Worker();
        manager3.setWorker(worker3);

        // 申请进入项目组有活干才可能不被优化
        ManagerGroup.addTask(manager1);
        ManagerGroup.addTask(manager2);
        ManagerGroup.addTask(manager3);
    }
}

可以自己将核心小组数量、最多能容纳的小队数量等数字调节一下,然后运行看看效果。

和线程一样,线程池也有自己的状态,而且和线程的状态差不多(想想也是,毕竟要符合线程生命周期的东西,确实应该差不多)。线程池状态:

 

 

1、RUNNING:正常运行,能接收新任务,也能处理阻塞队列中的任务;

2、SHUTDOWN:关闭状态,不接收新任务,但可以继续处理阻塞队列中已有任务;

3、STOP:既不接收新任务,也不处理队列中的任务,并会中断正在处理的任务;

4、TIDYING(这个名字叫得有点奇怪):如果所有任务都已中止,且workCount有效线程数为0,则会调用terminated()方法进入TERMINATED状态;

5、TERMINATED:terminated()方法执行完后进入该状态,什么也不做。

线程池运行时的流程图:

 

 

 至于线程池的构造函数什么的就不多啰嗦了,太枯燥无聊。

 

与Java多线程-ThreadPool线程池-1(三)相似的内容:

Java多线程-ThreadPool线程池-1(三)

开完一趟车完整的过程是启动、行驶和停车,但老司机都知道,真正费油的不是行驶,而是长时间的怠速、频繁地踩刹车等动作。因为在速度切换的过程中,发送机要多做一些工作,当然就要多费一些油。 而一个Java线程完整的生命周期就包括: 1、T1:创建(启动) 2、T2:运行(行驶) 3、T3:销毁(停车) 而T

Java多线程-ThreadPool线程池-3(五)

除了可以通过ThreadPoolExecutor自定义线程池外,同Stream API中的Collectors一样,多线程里的Executors类也提供了一组相关的线程池工具,可以直接拿来用,不用考虑用什么队列合适的问题。 Javac除了传统的四大线程池工具: 1、newFixedThreadPoo

Java多线程-ThreadPool线程池-2(四)

线程池是个神器,用得好会非常地方便。本来觉得线程池的构造器有些复杂,即使讲清楚了对今后的用处可能也不太大,因为有一些Java定义好的线程池可以直接使用。但是(凡事总有个但是),还是觉得讲一讲可能跟有助于理解后面的常用线程池,所以该打脸还是打吧 因为直接结合代码看会更清楚一些,所以我把带注释的代码贴出

Java多线程-JUC-1(八)

前面把线程相关的生命周期、关键字、线程池(ThreadPool)、ThreadLocal、CAS、锁和AQS都讲完了,现在就剩下怎么来用多线程了。而要想用好多线程,其实是可以取一些巧的,比如JUC(好多面试官喜欢问的JUC,就是现在要讲的JUC)。JUC就是java.util.concurrent的

Java多线程-ThreadLocal(六)

为了提高CPU的利用率,工程师们创造了多线程。但是线程们说:要有光!(为了减少线程创建(T1启动)和销毁(T3切换)的时间),于是工程师们又接着创造了线程池ThreadPool。就这样就可以了吗?——不,工程师们并不满足于此,他们不把自己创造出来的线程给扒个底朝天决不罢手。 有了线程关键字解决线程安

Java多线程

一.线程的生命周期及五种基本状态 关于Java中线程的生命周期,首先看一下下面这张较为经典的图: 上图中基本上囊括了Java中多线程各重要知识点。掌握了上图中的各知识点,Java中的多线程也就基本上掌握了。主要包括: Java线程具有五中基本状态 新建状态(New):当线程对象对创建后,即进入了新建

Java多线程生成波场靓号

​ 玩区块链,手上没靓号怎么行。用网上的靓号生成器有一定的风险性,思来想去决定自己写一个。首先需要导入波场官方编辑 org.tron.trident utils

java多线程编程:你真的了解线程中断吗?

java.lang.Thread类有一个 interrupt 方法,该方法直接对线程调用。当被interrupt的线程正在sleep或wait时,会抛出 InterruptedException 异常。事实上, interrupt 方法只是改变目标线程的中断状态(interrupt status),...

杰哥教你面试之一百问系列:java多线程

java多线程是java面试中的高频问题,如何才能在面试中脱颖而出呢?熟读这里的一百个java多线程面试问题即可。 ### 1. **什么是线程?什么是进程?** **回答:** - 线程是操作系统能够进行调度的最小执行单位,它包含在进程中,共享进程的资源。 - 进程是一个正在执行中的程序,它包含了

JAVA多线程并发编程-避坑指南

本篇旨在基于编码规范、工作中积累的研发经验等,整理在多线程开发的过程中需要注意的部分,比如不考虑线程池参数、线程安全、死锁等问题,将会存在潜在极大的风险。并且对其进行根因分析,避免每天踩一坑,坑坑不一样。