Java并发包(java.util.concurrent)阅读(一)ExecutorService ->ThreadPoolExecutor

ExecutorService是继承于Executor。ExecutorService,提供了为异步任务(Runable的实现类)创建Future的方法,用来管理任务执行的状态。而且提供管理终止的方法,导致会拒绝新的任务,他提供了两个关闭的方法,shutdown()(等待堆积的任务处理完后管理),shutdownNow(立即关闭,防止等待任务的执行并试图关闭现在正在运行的任务,并且返回一个List,包含了队列中等待任务),之后经行资源的回收。

下图是concurrent包下面的Executor子类继承/实现的关系图。

而ThreadPoolExecutor是JDK提供给ExecutorService的一个现实类,这个也是最常用的,会调用池中的可用线程来处理提交的任务,主要用来处理执行大量异步处理任务的时候,改善性能,减少每个任务的调度开销,并且提供了限制和管理线程的方法。


创建方法
主要的生成的方法是有两类,第一类是调用其构造器经常创建实例,第二就是调用Executors这个类经行创建。

一.调用构造器
先讲解调用构造函数,我挑选一个参数最全的构造器给大家讲解下参数,这样其他的构造器十分容易理解。

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

corePoolSize :直译过来的意思就是核心线程数, 而且会一直存活,即使一直处于空闲状态,线程池也会维护线程的最少数量。
maximumPoolSize:最大线程数,就是这个线程池能够达到的最多线程数
keepAliveTime:最大空闲时间,就是当线程空闲达到一定时候之后,而且当前线程数大于核心线程数,就是关闭该线程
unit: 线程池维护线程所允许的空闲时间的单位、可选参数值为:TimeUnit枚举里面的值
workQueue:工作队列,这个队列用于缓存未执行的任务,这个队列只保存通过{execute}这个方法提交的任务
threadFactory:线程工程,用于生产线程
handler:这个处理器用于当工作队列阻塞(达到最大数量)的时候,来处理任务的策略。 默认值ThreadPoolExecutor.AbortPolicy()。

处理器主要有这几种
* ThreadPoolExecutor.CallerRunsPolicy(),当任务被拒绝的时候,会处理器直接调用run()方法运行,如果线程池已经处于关闭状态,任务会丢失。
* ThreadPoolExecutor.AbortPolicy(),在向线程池提交的任务会被拒绝,并抛出异常。
* ThreadPoolExecutor.DiscardPolicy(),当任务被拒绝的时候 ,在向线程池提交的任务会被丢弃。
* ThreadPoolExecutor.DiscardOldestPolicy(),当任务被拒绝的时候 ,会调用工作队列poll()方法(将队列中头部信息取出并丢弃),再将新的任务通过线程池的execute()将任务插入,如果线程池已经处于关闭状态,任务会丢失。

二.调用工具类
另外比较常用的一个方式是使用Executors这个工具类来创建ExecutorService,在这个工具类中封装了一些常用的创建ExecutorService的方法,讲解下常用的几个方法。

newFixedThreadPool:用创建一个固定的线程池。方法参数有两个,线程数量和线程工厂,底层的队列用的是LinkedBlockingQueue,这个队列容量为Integer.MAX_VALUE。提交的都任务都会堆积在队列中,直到有可用的线程进行消费为止。

public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue(),
                                  threadFactory);
}

newCacheThreadPool:用创建一个缓存的线程池。这个线程池会根据需要创建新的线程来处理调度任务,但也会重用之前的创建的线程,减少开销。

//传入一个线程工厂(选填,可以调用重载方法)
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue(),
                                  threadFactory);
}

newSingleThreadExecutor:创建一个一个线程的线程池,保证提交的任务串行化执行,看下代码就发现,方法的返回不等价于newFixedThreadPool(1),这里返回的是FinalizableDelegatedExecutorService,但是再深入的看下这个类的代码就会发现实际执行过程是等价于newFixedThreadPool(1),为什么这么写我现在还没搞明白。

//传入一个线程工厂(选填,可以调用重载方法)
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue(),
                                threadFactory));
}

执行方法

ExecutorService提交单条任务的方法主要有两种,submit和executor。

//Executor接口下的
void execute(Runnable command);

submit方法是Executor接口中定义的方法,只能提交Runnable的任务,方法的返回值是空的。我们无法知道该任务运行情况。

//ExecutorService接口下的
  Future submit(Callable task);//传入一个Callable
  Future submit(Runnable task, T result);//传入一个Runnable,并自己设定Future返回值
 Future submit(Runnable task);//传入一个Runnable,Future返回值为null

submit方法是ExecutorService接口中定义的方法,可以提交Runnable和Callable两种任务,并且调用该方法之后我们可以收到Future这个返回值,可以调用
Future中定义的一些方法来获取任务执行状态,并管理任务。

在看下submit方法在AbstractExecutorService中的实现方法,方法中会先将Callable/Runnable封装成RunnableFuture(实际实例的类是FutureTask),再调用execute,将该任务提交到任务队列中,并将ftask返回出去,提供给我们进行监控管理。

    public Future submit(Runnable task) {
        if (task == null) throw new NullPointerException();//校验任务是否为空
        RunnableFuture ftask = newTaskFor(task, null);//为任务创建一个Future,提供给我们管理
        execute(ftask);//调用execute经行执行
        return ftask;//返回
    }

关闭ExecutorService
关闭方法有两个shutdown()和shutdownNow()。
前者是将线程池状态转换到关闭,不接受新的任务进入,关闭空闲线程,但是会继续消费队列中堆积的任务。
后者是线程池状态转换到停止,不接受新的任务进入,关闭全部线程,并把队列中堆积的数据都取出来并返回。

    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;//定义局部变量,将静态变量应用进来,个人觉得是因为,JMM和OOP有一定的差异导致的
        mainLock.lock();//先加锁确保线程安全
        try {
            checkShutdownAccess();//有关安全管理器的一些方法
            advanceRunState(SHUTDOWN);//将状态至为关闭
            interruptIdleWorkers();//中端空闲线程
            onShutdown(); // 为ScheduledThreadPoolExecutor这个类服务,在这里是个空方法
        } finally {
            mainLock.unlock();//解锁
        }
        tryTerminate();//尝试中断
    }
    public List shutdownNow() {
        List tasks;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();//先加锁确保线程安全
        try {
            checkShutdownAccess();//有关安全管理器的一些方法
            advanceRunState(STOP);//将状态至为停止
            interruptWorkers();//中断全部线程,会丢失正在运行的任务
            tasks = drainQueue();//取出队列中堆积的任务
        } finally {
            mainLock.unlock();//解锁
        }
        tryTerminate();//尝试中断
        return tasks;
    }

常用的一些方法主要就是这些。新手写博客,有什么问题麻烦大家给我提一下,谢谢
:)

你可能感兴趣的:(Java,源码阅读,并发包)