「java线程池怎么运行」java线程池工作流程

博主:adminadmin 2022-12-09 15:21:08 65

本篇文章给大家谈谈java线程池怎么运行,以及java线程池工作流程对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

java线程池怎么实现

要想理解清楚java线程池实现原理,明白下面几个问题就可以了:

(1):线程池存在哪些状态,这些状态之间是如何进行切换的呢?

(2):线程池的种类有哪些?

(3):创建线程池需要哪些参数,这些参数的具体含义是什么?

(4):将任务添加到线程池之后运行流程?

(5):线程池是怎么做到重用线程的呢?

(6):线程池的关闭

首先回答第一个问题:线程池存在哪些状态;

查看ThreadPoolExecutor源码便知晓:

[java] view plain copy

// runState is stored in the high-order bits

private static final int RUNNING    = -1  COUNT_BITS;

private static final int SHUTDOWN   =  0  COUNT_BITS;

private static final int STOP       =  1  COUNT_BITS;

private static final int TIDYING    =  2  COUNT_BITS;

private static final int TERMINATED =  3  COUNT_BITS;

存在5种状态:

1Running:可以接受新任务,同时也可以处理阻塞队列里面的任务;

2Shutdown:不可以接受新任务,但是可以处理阻塞队列里面的任务;

3Stop:不可以接受新任务,也不处理阻塞队列里面的任务,同时还中断正在处理的任务;

4Tidying:属于过渡阶段,在这个阶段表示所有的任务已经执行结束了,当前线程池中是不存在有效的线程的,并且将要调用terminated方法;

5Terminated:终止状态,这个状态是在调用完terminated方法之后所处的状态;

那么这5种状态之间是如何进行转换的呢?查看ThreadPoolExecutor源码里面的注释便可以知道啦:

[java] view plain copy

* RUNNING - SHUTDOWN

*    On invocation of shutdown(), perhaps implicitly in finalize()

* (RUNNING or SHUTDOWN) - STOP

*    On invocation of shutdownNow()

* SHUTDOWN - TIDYING

*    When both queue and pool are empty

* STOP - TIDYING

*    When pool is empty

* TIDYING - TERMINATED

*    When the terminated() hook method has completed

从上面可以看到,在调用shutdown方法的时候,线程池状态会从Running转换成Shutdown;在调用shutdownNow方法的时候,线程池状态会从Running/Shutdown转换成Stop;在阻塞队列为空同时线程池为空的情况下,线程池状态会从Shutdown转换成Tidying;在线程池为空的情况下,线程池状态会从Stop转换成Tidying;当调用terminated方法之后,线程池状态会从Tidying转换成Terminate;

在明白了线程池的各个状态以及状态之间是怎么进行切换之后,我们来看看第二个问题,线程池的种类:

(1):CachedThreadPool:缓存线程池,该类线程池中线程的数量是不确定的,理论上可以达到Integer.MAX_VALUE个,这种线程池中的线程都是非核心线程,既然是非核心线程,那么就存在超时淘汰机制了,当里面的某个线程空闲时间超过了设定的超时时间的话,就会回收掉该线程;

(2):FixedThreadPool:固定线程池,这类线程池中是只存在核心线程的,对于核心线程来说,如果我们不设置allowCoreThreadTimeOut属性的话是不存在超时淘汰机制的,这类线程池中的corePoolSize的大小是等于maximumPoolSize大小的,也就是说,如果线程池中的线程都处于活动状态的话,如果有新任务到来,他是不会开辟新的工作线程来处理这些任务的,只能将这些任务放到阻塞队列里面进行等到,直到有核心线程空闲为止;

(3):ScheduledThreadPool:任务线程池,这种线程池中核心线程的数量是固定的,而对于非核心线程的数量是不限制的,同时对于非核心线程是存在超时淘汰机制的,主要适用于执行定时任务或者周期性任务的场景;

(4):SingleThreadPool:单一线程池,线程池里面只有一个线程,同时也不存在非核心线程,感觉像是FixedThreadPool的特殊版本,他主要用于确保任务在同一线程中的顺序执行,有点类似于进行同步吧;

接下来我们来看第三个问题,创建线程池需要哪些参数:

同样查看ThreadPoolExecutor源码,查看创建线程池的构造函数:

[java] view plain copy

public ThreadPoolExecutor(int corePoolSize,

int maximumPoolSize,

long keepAliveTime,

TimeUnit unit,

BlockingQueueRunnable workQueue,

ThreadFactory threadFactory,

RejectedExecutionHandler handler)

不管你调用的是ThreadPoolExecutor的哪个构造函数,最终都会执行到这个构造函数的,这个构造函数有7个参数,正是由于对这7个参数值的赋值不同,造成生成不同类型的线程池,比如我们常见的CachedThreadPoolExecutor、FixedThreadPoolExecutor

SingleThreadPoolExecutor、ScheduledThreadPoolExecutor,我们老看看这几个参数的具体含义:

1corePoolSize:线程池中核心线程的数量;当提交一个任务到线程池的时候,线程池会创建一个线程来执行执行任务,即使有其他空闲的线程存在,直到线程数达到corePoolSize时不再创建,这时候会把提交的新任务放入到阻塞队列中,如果调用了线程池的preStartAllCoreThreads方法,则会在创建线程池的时候初始化出来核心线程;

2maximumPoolSize:线程池允许创建的最大线程数;如果阻塞队列已经满了,同时已经创建的线程数小于最大线程数的话,那么会创建新的线程来处理阻塞队列中的任务;

3keepAliveTime:线程活动保持时间,指的是工作线程空闲之后继续存活的时间,默认情况下,这个参数只有线程数大于corePoolSize的时候才会起作用,即当线程池中的线程数目大于corePoolSize的时候,如果某一个线程的空闲时间达到keepAliveTime,那么这个线程是会被终止的,直到线程池中的线程数目不大于corePoolSize;如果调用allowCoreThreadTimeOut的话,在线程池中线程数量不大于corePoolSize的时候,keepAliveTime参数也可以起作用的,知道线程数目为0为止;

4unit:参数keepAliveTime的时间单位;

5workQueue:阻塞队列;用于存储等待执行的任务,有四种阻塞队列类型,ArrayBlockingQueue(基于数组的有界阻塞队列)、LinkedBlockingQueue(基于链表结构的阻塞队列)、SynchronousQueue(不存储元素的阻塞队列)、PriorityBlockingQueue(具有优先级的阻塞队列);

6threadFactory:用于创建线程的线程工厂;

7handler:当阻塞队列满了,且没有空闲线程的情况下,也就是说这个时候,线程池中的线程数目已经达到了最大线程数量,处于饱和状态,那么必须采取一种策略来处理新提交的任务,我们可以自己定义处理策略,也可以使用系统已经提供给我们的策略,先来看看系统为我们提供的4种策略,AbortPolicy(直接抛出异常)、CallerRunsPolicy(只有调用者所在的线程来运行任务)、DiscardOldestPolicy(丢弃阻塞队列中最近的一个任务,并执行当前任务)、Discard(直接丢弃);

接下来就是将任务添加到线程池之后的运行流程了;

我们可以调用submit或者execute方法,两者最大的区别在于,调用submit方法的话,我们可以传入一个实现Callable接口的对象,进而能在当前任务执行结束之后通过Future对象获得任务的返回值,submit内部实际上还是执行的execute方法;而调用execute方法的话,是不能获得任务执行结束之后的返回值的;此外,调用submit方法的话是可以抛出异常的,但是调用execute方法的话,异常在其内部得到了消化,也就是说异常在其内部得到了处理,不会向外传递的;

因为submit方法最终也是会执行execute方法的,因此我们只需要了解execute方法就可以了:

在execute方法内部会分三种情况来进行处理:

1:首先判断当前线程池中的线程数量是否小于corePoolSize,如果小于的话,则直接通过addWorker方法创建一个新的Worker对象来执行我们当前的任务;

2:如果说当前线程池中的线程数量大于corePoolSize的话,那么会尝试将当前任务添加到阻塞队列中,然后第二次检查线程池的状态,如果线程池不在Running状态的话,会将刚刚添加到阻塞队列中的任务移出,同时拒绝当前任务请求;如果第二次检查发现当前线程池处于Running状态的话,那么会查看当前线程池中的工作线程数量是否为0,如果为0的话,就会通过addWorker方法创建一个Worker对象出来处理阻塞队列中的任务;

3:如果原先线程池就不处于Running状态或者我们刚刚将当前任务添加到阻塞队列的时候出现错误的话,那么会去尝试通过addWorker创建新的Worker来处理当前任务,如果添加失败的话,则拒绝当前任务请求;

可以看到在上面的execute方法中,我们仅仅只是检查了当前线程池中的线程数量有没有超过corePoolSize的情况,那么当前线程池中的线程数量有没有超过maximumPoolSize是在哪里检测的呢?实际上是在addWorker方法里面了,我们可以看下addWorker里面的一段代码:

[java] view plain copy

if (wc = CAPACITY ||

wc = (core ? corePoolSize : maximumPoolSize))

return false;

如果当前线程数量超过maximumPoolSize的话,直接就会调用return方法,返回false;

其实到这里我们很明显可以知道,一个线程池中线程的数量实际上就是这个线程池中Worker的数量,如果Worker的大小超过了corePoolSize,那么任务都在阻塞队列里面了,Worker是Java对我们任务的一个封装类,他的声明是酱紫的:

[java] view plain copy

private final class Worker

extends AbstractQueuedSynchronizer

implements Runnable

可以看到他实现了Runnable接口,他是在addWorker方法里面通过new Worker(firstTask)创建的,我们来看看他的构造函数就知道了:

[java] view plain copy

Worker(Runnable firstTask) {

setState(-1); // inhibit interrupts until runWorker

this.firstTask = firstTask;

this.thread = getThreadFactory().newThread(this);

}

而这里的firstTask其实就是我们调用execute或者submit的时候传入的那个参数罢了,一般来说这些参数是实现Callable或者Runnable接口的;

在通过addWorker方法创建出来Worker对象之后,这个方法的最后会执行Worker内部thread属性的start方法,而这个thread属性实际上就是封装了Worker的Thread,执行他的start方法实际上执行的是Worker的run方法,因为Worker是实现了Runnable接口的,在run方法里面就会执行runWorker方法,而runWorker方法里面首先会判断当前我们传入的任务是否为空,不为空的话直接就会执行我们通过execute或者submit方法提交的任务啦,注意一点就是我们虽然会通过submit方法提交实现了Callable接口的对象,但是在调用submit方法的时候,其实是会将Callable对象封装成实现了Runnable接口对象的,不信我们看看submit方法源码是怎么实现的:

[java] view plain copy

public T FutureT submit(CallableT task) {

if (task == null) throw new NullPointerException();

RunnableFutureT ftask = newTaskFor(task);

execute(ftask);

return ftask;

}

看到没有呢,实际上在你传入实现了Callable接口对象的时候,在submit方法里面是会将其封装成RunnableFuture对象的,而RunnableFuture接口是继承了Runnable接口的;那么说白了其实就是直接执行我们提交任务的run方法了;如果为空的话,则会通过getTask方法从阻塞队列里面拿出一个任务去执行;在任务执行结束之后继续从阻塞队列里面拿任务,直到getTask的返回值为空则退出runWorker内部循环,那么什么情况下getTask返回为空呢?查看getTask方法的源码注释可以知道:在Worker必须需要退出的情况下getTask会返回空,具体什么情况下Worker会退出呢?(1):当Worker的数量超过maximumPoolSize的时候;(2):当线程池状态为Stop的时候;(3):当线程池状态为Shutdown并且阻塞队列为空的时候;(4):使用等待超时时间从阻塞队列中拿数据,但是超时之后仍然没有拿到数据;

如果runWorker方法退出了它里面的循环,那么就说明当前阻塞队列里面是没有任务可以执行的了,你可以看到在runWorker方法内部的finally语句块中执行了processWorkerExit方法,用来对Worker对象进行回收操作,这个方法会传入一个参数表示需要删除的Worker对象;在进行Worker回收的时候会调用tryTerminate方法来尝试关闭线程池,在tryTerminate方法里面会检查是否有Worker在工作,检查线程池的状态,没问题的话就会将当前线程池的状态过渡到Tidying,之后调用terminated方法,将线程池状态更新到Terminated;

从上面的分析中,我们可以看出线程池运行的4个阶段:

(1):poolSize corePoolSize,则直接创建新的线程(核心线程)来执行当前提交的任务;

(2):poolSize = corePoolSize,并且此时阻塞队列没有满,那么会将当前任务添加到阻塞队列中,如果此时存在工作线程(非核心线程)的话,那么会由工作线程来处理该阻塞队列中的任务,如果此时工作线程数量为0的话,那么会创建一个工作线程(非核心线程)出来;

(3):poolSize = corePoolSize,并且此时阻塞队列已经满了,那么会直接创建新的工作线程(非核心线程)来处理阻塞队列中的任务;

(4):poolSize = maximumPoolSize,并且此时阻塞队列也满了的话,那么会触发拒绝机制,具体决绝策略采用的是什么就要看我们创建ThreadPoolExecutor的时候传入的RejectExecutionHandler参数了;

接下来就是线程池是怎么做到重用线程的呢?

个人认为线程池里面重用线程的工作是在getTask里面实现的,在getTask里面是存在两个for死循环嵌套的,他会不断的从阻塞对列里面取出需要执行的任务,返回给我们的runWorker方法里面,而在runWorker方法里面只要getTask返回的任务不是空就会执行该任务的run方法来处理它,这样一直执行下去,直到getTask返回空为止,此时的情况就是阻塞队列里面没有任务了,这样一个线程处理完一个任务之后接着再处理阻塞队列中的另一个任务,当然在线程池中的不同线程是可以并发处理阻塞队列中的任务的,最后在阻塞队列内部不存在任务的时候会去判断是否需要回收Worker对象,其实Worker对象的个数就是线程池中线程的个数,至于什么情况才需要回收,上面已经说了,就是四种情况了;

最后就是线程池是怎样被关闭的呢?

涉及到线程池的关闭,需要用到两个方法,shutdown和shutdownNow,他们都是位于ThreadPoolExecutor里面的,对于shutdown的话,他会将线程池状态切换成Shutdown,此时是不会影响对阻塞队列中任务执行的,但是会拒绝执行新加进来的任务,同时会回收闲置的Worker;而shutdownNow方法会将线程池状态切换成Stop,此时既不会再去处理阻塞队列里面的任务,也不会去处理新加进来的任务,同时会回收所有Worker;

java线程池(一) 简述线程池的几种使用方式

首先说明下java线程是如何实现线程重用的

1. 线程执行完一个Runnable的run()方法后,不会被杀死

2. 当线程被重用时,这个线程会进入新Runnable对象的run()方法12

java线程池由Executors提供的几种静态方法创建线程池。下面通过代码片段简单介绍下线程池的几种实现方式。后续会针对每个实现方式做详细的说明

newFixedThreadPool

创建一个固定大小的线程池

添加的任务达到线程池的容量之后开始加入任务队列开始线程重用总共开启线程个数跟指定容量相同。

@Test

public void newFixedThreadPool() throws Exception {

ExecutorService executorService = Executors.newFixedThreadPool(1);

executorService = Executors.newFixedThreadPool(1, new ThreadFactoryBuilder().build());

RunThread run1 = new RunThread("run 1");

executorService.execute(run1);

executorService.shutdown();

}12345678

newSingleThreadExecutor

仅支持单线程顺序处理任务

@Test

public void newSingleThreadExecutor() throws Exception {

ExecutorService executorService = Executors.newSingleThreadExecutor();

executorService = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().build());

executorService.execute(new RunThread("run 1"));

executorService.execute(new RunThread("run 2"));

executorService.shutdown();

}123456789

newCachedThreadPool

这种情况跟第一种的方式类似,不同的是这种情况线程池容量上线是Integer.MAX_VALUE 并且线程池开启缓存60s

@Test

public void newCachedThreadPool() throws Exception {

ExecutorService executorService = Executors.newCachedThreadPool();

executorService = Executors.newCachedThreadPool(new ThreadFactoryBuilder().build());

executorService.execute(new RunThread("run 1"));

executorService.execute(new RunThread("run 2"));

executorService.shutdown();

}123456789

newWorkStealingPool

支持给定的并行级别,并且可以使用多个队列来减少争用。

@Test

public void newWorkStealingPool() throws Exception {

ExecutorService executorService = Executors.newWorkStealingPool();

executorService = Executors.newWorkStealingPool(1);

RunThread run1 = new RunThread("run 1");

executorService.execute(run1);

executorService.shutdown();

}123456789

newScheduledThreadPool

看到的现象和第一种相同,也是在线程池满之前是新建线程,然后开始进入任务队列,进行线程重用

支持定时周期执行任务(还没有看完)

@Test

public void newScheduledThreadPool() throws Exception {

ExecutorService executorService = Executors.newScheduledThreadPool(1);

executorService = Executors.newScheduledThreadPool(1, new ThreadFactoryBuilder().build());

executorService.execute(new RunThread("run 1"));

executorService.execute(new RunThread("run 2"));

executorService.shutdown();

}

Java 线程池是如何工作的

创建线程要花费昂贵的资源和时间,如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限。为了避免这些问题,在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程。从JDK1.5开始,Java API提供了Executor框架让你可以创建不同的线程池。比如单线程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合很多生存期短的任务的程序的可扩展线程池)。

java线程池怎么实现的

线程池简介:

多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。

假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。

如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。

一个线程池包括以下四个基本组成部分:

1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;

2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;

3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;

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

线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。

线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一个例子:

假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。

代码实现中并没有实现任务接口,而是把Runnable对象加入到线程池管理器(ThreadPool),然后剩下的事情就由线程池管理器(ThreadPool)来完成了

package mine.util.thread;  

  

import java.util.LinkedList;  

import java.util.List;  

  

/** 

 * 线程池类,线程管理器:创建线程,执行任务,销毁线程,获取线程基本信息 

 */  

public final class ThreadPool {  

    // 线程池中默认线程的个数为5  

    private static int worker_num = 5;  

    // 工作线程  

    private WorkThread[] workThrads;  

    // 未处理的任务  

    private static volatile int finished_task = 0;  

    // 任务队列,作为一个缓冲,List线程不安全  

    private ListRunnable taskQueue = new LinkedListRunnable();  

    private static ThreadPool threadPool;  

  

    // 创建具有默认线程个数的线程池  

    private ThreadPool() {  

        this(5);  

    }  

  

    // 创建线程池,worker_num为线程池中工作线程的个数  

    private ThreadPool(int worker_num) {  

        ThreadPool.worker_num = worker_num;  

        workThrads = new WorkThread[worker_num];  

        for (int i = 0; i  worker_num; i++) {  

            workThrads[i] = new WorkThread();  

            workThrads[i].start();// 开启线程池中的线程  

        }  

    }  

  

    // 单态模式,获得一个默认线程个数的线程池  

    public static ThreadPool getThreadPool() {  

        return getThreadPool(ThreadPool.worker_num);  

    }  

  

    // 单态模式,获得一个指定线程个数的线程池,worker_num(0)为线程池中工作线程的个数  

    // worker_num=0创建默认的工作线程个数  

    public static ThreadPool getThreadPool(int worker_num1) {  

        if (worker_num1 = 0)  

            worker_num1 = ThreadPool.worker_num;  

        if (threadPool == null)  

            threadPool = new ThreadPool(worker_num1);  

        return threadPool;  

    }  

  

    // 执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定  

    public void execute(Runnable task) {  

        synchronized (taskQueue) {  

            taskQueue.add(task);  

            taskQueue.notify();  

        }  

    }  

  

    // 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定  

    public void execute(Runnable[] task) {  

        synchronized (taskQueue) {  

            for (Runnable t : task)  

                taskQueue.add(t);  

            taskQueue.notify();  

        }  

    }  

  

    // 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定  

    public void execute(ListRunnable task) {  

        synchronized (taskQueue) {  

            for (Runnable t : task)  

                taskQueue.add(t);  

            taskQueue.notify();  

        }  

    }  

  

    // 销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁  

    public void destroy() {  

        while (!taskQueue.isEmpty()) {// 如果还有任务没执行完成,就先睡会吧  

            try {  

                Thread.sleep(10);  

            } catch (InterruptedException e) {  

                e.printStackTrace();  

            }  

        }  

        // 工作线程停止工作,且置为null  

        for (int i = 0; i  worker_num; i++) {  

            workThrads[i].stopWorker();  

            workThrads[i] = null;  

        }  

        threadPool=null;  

        taskQueue.clear();// 清空任务队列  

    }  

  

    // 返回工作线程的个数  

    public int getWorkThreadNumber() {  

        return worker_num;  

    }  

  

    // 返回已完成任务的个数,这里的已完成是只出了任务队列的任务个数,可能该任务并没有实际执行完成  

    public int getFinishedTasknumber() {  

        return finished_task;  

    }  

  

    // 返回任务队列的长度,即还没处理的任务个数  

    public int getWaitTasknumber() {  

        return taskQueue.size();  

    }  

  

    // 覆盖toString方法,返回线程池信息:工作线程个数和已完成任务个数  

    @Override  

    public String toString() {  

        return "WorkThread number:" + worker_num + "  finished task number:"  

                + finished_task + "  wait task number:" + getWaitTasknumber();  

    }  

  

    /** 

     * 内部类,工作线程 

     */  

    private class WorkThread extends Thread {  

        // 该工作线程是否有效,用于结束该工作线程  

        private boolean isRunning = true;  

  

        /* 

         * 关键所在啊,如果任务队列不空,则取出任务执行,若任务队列空,则等待 

         */  

        @Override  

        public void run() {  

            Runnable r = null;  

            while (isRunning) {// 注意,若线程无效则自然结束run方法,该线程就没用了  

                synchronized (taskQueue) {  

                    while (isRunning  taskQueue.isEmpty()) {// 队列为空  

                        try {  

                            taskQueue.wait(20);  

                        } catch (InterruptedException e) {  

                            e.printStackTrace();  

                        }  

                    }  

                    if (!taskQueue.isEmpty())  

                        r = taskQueue.remove(0);// 取出任务  

                }  

                if (r != null) {  

                    r.run();// 执行任务  

                }  

                finished_task++;  

                r = null;  

            }  

        }  

  

        // 停止工作,让该线程自然执行完run方法,自然结束  

        public void stopWorker() {  

            isRunning = false;  

        }  

    }  

}

线程池的使用

首先看看 阿里java规范 中对线程池使用的规范

不允许使用Executors创建线程池,创建的线程池数量可以为Integer.MAX_VALUE,可能导致OOM

推荐使用

ThreadPoolExecutor创建

看看其4构造方法

看参数最多的一个,上面的都是调这个方法

翻译一下

ThreadPoolExecutor(核心线程大小, 最大线程数,线程保持时间,保持时间单位, 缓存队列,线程工厂,拒绝策略)

前四个比较容易理解,看后面几个就好了

缓存队列:任务多的时候,没有多余线程执行任务,这些任务去队列排队,先进先出的原则,这里队列大小是有限制的,队排满了怎么办,用后面的拒绝策略来处理

线程工厂:

继承java.util.concurrent.ThreadFactory,下面是可用的两个工厂

拒绝策略:队列满了,后面的任务排不进去怎么处理,四种策略

1.AbortPolicy(终止策略)

这是一个处理器针对被拒绝的任务 直接抛出RejectedExecutionException异常(任务无法执行抛出异常)

2.DiscardPolicy(丢弃策略)

什么都不做,也不抛出异常

3.DiscardOldestPolicy(丢弃旧任务策略)

一种被拒绝任务的处理程序,它丢弃(workQueue队列)最老的未被处理请求(队列最先被放进去的任务),然后调用e.execute(r)重试执行当前任务(注意依然要走流程),除非执行器关闭,在这种情况下任务被丢弃。

4.CallerRunsPolicy(调用方运行策略)

被拒绝任务的处理程序,它直接由提交任务的线程来运行这个提交的任务,除非executor已关闭,在这种情况下任务被丢弃。

测试一下

执行结果

1、核心线程先初始化一个线程

2、第1个任务直接给线程

3、第2-6加入队列,装满了

4、第7-10需创建线程用于执行任务

5、到此队列5个和线程五个一起最多处理10任务,第11个任务拒绝处理,等待中...

6、继续执行,利用释放的线程和队列继续处理(优先使用线程,没有加入队列)...

java线程池怎么运行的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于java线程池工作流程、java线程池怎么运行的信息别忘了在本站进行查找喔。

The End

发布于:2022-12-09,除非注明,否则均为首码项目网原创文章,转载请注明出处。