6.1 线程池的优点、以及各个参数的意义、使用示例

线程池的有点:省时、省资源、更好管理线程 

1、减少资源的消耗:较少线程创建和销毁造成的消耗

2、提高响应速度:当任务到达的时候,就能够立刻执行,减少了线程创建和销毁的时间

3、能够更好地管理线程

ThreadPoolExecutor 的类关系

Executor:接口,是线程池的基础,将任务的提交与任务的执行分离开来。

ExecutorService:接口:继承了Executor,新加了shutdown(),submit()

AbstractExecutorService:实现了ExecutorService大部分方法,可以少写很多代码

ThreadPoolExecutor:线程池的核心实现了,用来执行被提交的任务

ScheduledExecutorService:提供了带周期执行的ExecutorService

ScheduledThreadPoolExecutor:可以延迟执行任务

线程池的创建各个参数含义

完整的构造函数

public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)

corePoolSize

线程池中的核心线程数,当提交一个任务时,线程池创建一个新线程执行任务,直到线程数=corePoolSize,之后提交的任务会被保存到阻塞队列中,等待被执行。

备注:如果执行了线程池的prestartAllCoreThreads()方法,线程池会提前创建好corePoolSize数量的线程,提高效率

maximumPoolSize

如果线程数=corePoolSize,且阻塞队列也被塞满了,这个时候再提交任务,就会再创建线程执行任务,但是线程池总线程数必须<=maximumPoolSize

keepAliveTime

当线程数>corePoolSize时,当前线程没有任务执行,线程继续存活的时间

线程空闲时的存活时间,即当线程没有任务执行时,继续存活的时间。默认情况下,该参数只在线程数大于corePoolSize时才有用

TimeUnit

keepAliveTime线程存活的时间单位

关于小时的常用方法  

TimeUnit.HOURS.toMillis(1) 1小时转分
TimeUnit.HOURS.toMinutes(60) 60小时转分
TimeUnit.HOURS.sleep(5)  线程休眠5秒
TimeUnit.HOURS.convert(1, TimeUnit.MINUTES)  1小时转秒

常用工具类

TimeUnit.DAYS  日的工具类
TimeUnit.HOURS 时的工具类 
TimeUnit.MINUTES  分的工具类
TimeUnit.SECONDS  秒的工具类 
TimeUnit.MILLISECONDS 毫秒的工具类

workQueue

workQueue必须是BlockingQueue阻塞队列:当线程池的线程数超过corePoolSize的时候,多余的线程就会进入阻塞队列中,等待被执行

应当尽量使用有界阻塞队列,比如:LinkedBlockingQueue、ArrayBlokngQueue、SynchronousQueue、PriorityBlockingQueue,使用无界阻塞队列(比如:DelayQueue、LinkedtransferQueue)会产生如下影响

1、当线程数超过corePoolSize之后,其他线程就会放在无界队列中等待,就不会再创建新的线程来执行任务了,导致界队列时maximumPoolSize将是一个无效参数。

2、由于1,使用无界队列的keepAliveTime参数无效

3、无界队列可能会耗尽系统资源

threadFactory

创建线程的工厂,使用场景

1、通过自定义的线程工厂,给每个新建的线程设置一个有识别度的线程名

2、通过线程工厂把所有的线程设置为守护线程

demo

public class Test {
    public static void main(String[] args) {

        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                10,
                20,
                20,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(10), new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                //1、设置线程的名字
                Thread thread = new Thread(r);
                //thread.setName("通过自定义线程工厂谁知线程名字");
                //2、设置成守护线程
                //thread.setDaemon(true);
                return thread;
            }
        },
//                new ThreadPoolExecutor.CallerRunsPolicy());
//                new ThreadPoolExecutor.DiscardOldestPolicy());
//                new ThreadPoolExecutor.DiscardPolicy());
                new AbortPolicy());

    }
}

RejectedExecutionHandler

当阻塞队列被塞满了,并且没有多余的线程执行任务的时候,对于新添加进来的任务必须做一个处理

AbortPolicy 默认:直接抛异常
CallerRunsPolicy 用调用者线程来执行(比如main)
DiscardOldestPolicy 丢掉队列中最靠前的任务,并执行当前任务
DiscardPolicy 直接丢掉任务
实现RejectedExecutionHandler 日志记录或者持久化存储

demo

public class Test {
    public static void main(String[] args) {

        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                10,
                20,
                20,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(10), new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                //1、设置线程的名字
                Thread thread = new Thread(r);
                //thread.setName("通过自定义线程工厂谁知线程名字");
                //2、设置成守护线程
                //thread.setDaemon(true);
                return thread;
            }
        },
//                new ThreadPoolExecutor.CallerRunsPolicy());
//                new ThreadPoolExecutor.DiscardOldestPolicy());
//                new ThreadPoolExecutor.DiscardPolicy());
                new AbortPolicy());

    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章