ThreadPool study

线程池浅析

线程池顾名思义就是放线程的池子 Thread Pool。

那么为什么要有线程池呢?有些时候系统需要处理非常多的执行时间很短的请求,如果每一个请求都开启一个新的线程,则系统创建销毁线程的开销就太大了,甚至在创建和销毁线程的时间比任务的执行时间还长。

使用new Thread() 会有如下缺点:

1.创建和销毁线程耗费大量系统资源;

2.每次new Thread() 缺乏线程管理,被称为野线程,而且可以无限制创建,之间相互竞争,会导致过多占用系统资源导致系统瘫痪。

3.不利于扩展,如定期执行,定时执行,线程中断。

线程池主要解决了两个问题:

       1.通过重用线程,达到减少每个线程创建和销毁的性能开销。

       2.对线程进行一些维护,比如定时开始,周期执行,并发控制等。

       3.可控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争。

Executor:JDK1.5引入,内部使用线程池机制,在java.util.cocurrent包下,Executor框架包括:线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable,ThreadPoolExecutor等。

Executors:工厂类 创建线程池

1.newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {

    return new ThreadPoolExecutor(nThreads, nThreads,

                                  0L, TimeUnit.MILLISECONDS,

                                  new LinkedBlockingQueue<Runnable>());

}

 

创建一个固定数目的线程池,内部维持一个无界的队列,当所有的线程都在处于活动状态时提交了其他任务,则新任务将在队列中等待直到线程可用。

2.newCachedThreadPool
public static ExecutorService newCachedThreadPool() 
{

    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,

                                  60L, TimeUnit.SECONDS,

                                  new SynchronousQueue<Runnable>());

}

 

创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。

该线程池适用于执行许多短暂异步任务的程序,调用execute会重用以前构造的线程,如果没有可用的线程,则会创建新的线程,并将该线程添加到该池中,未使用60秒的线程将被终止并从缓存中删除。因此,长时间保持闲置的池将不会消耗任何资源。

3.newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {

    return new FinalizableDelegatedExecutorService

        (new ThreadPoolExecutor(1, 1,

                                0L, TimeUnit.MILLISECONDS,

                                new LinkedBlockingQueue<Runnable>()));

}

 

创建一个使用无界队列运行单个工作线程的执行程序,等效于newFixedThreadPool(1)

4.newScheduledThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {

    return new ScheduledThreadPoolExecutor(corePoolSize);

}

 

创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执行。

scheduleAtFixedRate(Runnable command,
                                                 long initialDelay,
                                                 long delay,
                                                 TimeUnit unit);

首次执行在 initialDelay 之后,第二次 执行时间为 initialDelay+delay*1 ….

scheduleWithFixedDelay(Runnable command,
                                                 long initialDelay,
                                                 long delay,
                                                 TimeUnit unit);

第一次的执行时间为 当前时间+ initialDelay,第二次为第一次执行结束时间+delay

ExecutorService 的submit() 和 execute()区别:

1.入参不同 submit可以接收Runnable或者Callable ,execute方法只能接收Runnable

2.返回值 submit 有返回值 而 execute没有返回值

3.submit方便处理Exception  Future.get抛出的异常

Runnable和Callable的区别

Callable接口中的call方法是有返回值的,泛型可任意制定,但是Runnable接口中run方法是没有返回值的。

ThreadPoolExecutor:JDK提供的Executors工具类中创建的线程无法满足使用场景时,则需要手动配置和调优,则用到该池。

public ThreadPoolExecutor(int corePoolSize,

                          int maximumPoolSize,

                          long keepAliveTime,

                          TimeUnit unit,

                          BlockingQueue<Runnable> workQueue) {

    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,

         Executors.defaultThreadFactory(), defaultHandler);

}

参数详解:

corePoolSize:核心线程数

maximumPoolSize:最大线程数

keepAliveTime:最大空闲时间

BlockingQueue:使用的任务队列

               ArrayBlockingQueue:底层是数组的定长任务队列,必须制定长度,可设置是               否公平锁。默认先进先出

               LinkedBlockingQueue:底层为链表的可定长任务队列,不指定长度则为无界,             可设置公平锁,默认为先进先出

               SynchronousQueue:同步的没有缓冲的任务队列,只有当线程将队列中的take走之后,才能新加进来任务

defaultHandler:该参数代表的是拒绝策略,默认为AbortPolicy

可以通过设置改变

/**
 * ThreadPoolExecutor.AbortPolicy() 
抛出java.util.concurrent.RejectedExecutionException异常
 
* ThreadPoolExecutor.CallerRunsPolicy() 使用主线程跑当前任务
 
* ThreadPoolExecutor.DiscardOldestPolicy() 抛弃旧的任务
 
* ThreadPoolExecutor.DiscardPolicy() 抛弃当前的任务
 
*/
posted @ 2018-11-05 19:27  宅小涛  阅读(137)  评论(0编辑  收藏  举报