5、java的concurrent包下的线程池

1、java.util.concurrent

    Class Executurs

public class Executors extends Object

其中提供了返回类型为Executor、ExecutorService、ScheduledExecutorService、ThreadFactory和Callable的方法。

 

public static ExecutorService newFixedThreadPool(int nThreads)

创建一个固定线程个数的线程池。当所有的线程都处于活跃状态,此时有一个任务提交到线程池,那么任务将会处于等待状态,直到线程池当中有可用的线程。当线程在执行任务时间

由于某些原因而消亡,那么一个新的线程将会替换它来完成后续的任务。这些线程将会一直存在于线程池除非被显性的shutdown。

 

public static ExecutorService newSingleThreadExecutor()

创建一个单一的线程。如果线程在处理任务时,由于某种原因消亡,那么会有一个新的线程来替换它继续执行后续的任务。

 

public static ExecutorService newCachedThreadPool()

按需创建线程的线程池,但是当线程池当中的线程处于可用状态时,它们能够复用。这个池能够改善执行许多生命周期短的异步任务的性能。线程如果在60s之内没有被利用,就会被中止,

并且移除线程池。

 

public static ScheduleExecutorService newSingleThreadScheduleExecutor()

创建一个单一的线程执行器(executor),它能够在给定的延迟时间或者以一定的频率来调度任务。

 

public static ScheduleExecutorService newScheduledThreadPool(int corePoolSize)

 

public static Callable<Object> callable(Runnable task)

运行一个给定的任务,并且返回一个Callable对象

 

2、层级关系

interface Executor;

interface ExecutorService implements Executor;

abstract class AbstractExecutorService implements ExecutorService

class ThreadPoolExecutor extends AbstractExecutorService;

 1     /**
 2      * @param corePoolSize 保持在池中的线程数,即使它们处于空闲状态,除非allowCoreThreadTimeOut设置了
 3      * @param maximumPoolSize 允许在池中的最大线程数
 4      * @param keepAliveTime 当池中的线程数大于核心线程数时,多于核心线程数的那部分线程等待新任务的最大时间为keepAliveTime,如果这段时间内没有新任务,那么这些线程将会终止。
 5      * @param unit 为keepAliveTime设置时间单元
 6      * @param workQueue 在任务被执行前,它们都存储在workQueue当中。这个队列指挥保留通过execute方法提交的Runnable任务。
 7      * @param threadFactory 创建新线程将用到的线程工厂
 8      * @param handler 由于线程大小数和队列容量已经达到边界,执行就会被阻塞,此时会执行handler。即,提供了在到达界限时,希望做的事。
 9      */
10     public ThreadPoolExecutor(int corePoolSize,
11                               int maximumPoolSize,
12                               long keepAliveTime,
13                               TimeUnit unit,
14                               BlockingQueue<Runnable> workQueue,
15                               ThreadFactory threadFactory,
16                               RejectedExecutionHandler handler) {
17         if (corePoolSize < 0 ||
18             maximumPoolSize <= 0 ||
19             maximumPoolSize < corePoolSize ||
20             keepAliveTime < 0)
21             throw new IllegalArgumentException();
22         if (workQueue == null || threadFactory == null || handler == null)
23             throw new NullPointerException();
24         this.corePoolSize = corePoolSize;
25         this.maximumPoolSize = maximumPoolSize;
26         this.workQueue = workQueue;
27         this.keepAliveTime = unit.toNanos(keepAliveTime);
28         this.threadFactory = threadFactory;
29         this.handler = handler;
30     }

 

线程池有它自己的生命周期,在这个生命周期中有五个状态,然后线程池还有一个“线程数”的属性。这六个属性线程池是用一个变量来表示的,这就是ctl控制状态符。

它是一个原子态的整型(AtomicInteger),它表示了概念上的两个属性:

wokerCount:指示了有效的线程数

runState:指示了running、shutting down等等这些状态。

为了将这些打包进一个int类型的数据,于是限制了wokerCount数目最多为(2^9-1,大约500million,5亿)个线程而不是(2^31-1,2billion,20亿)。当然如果将来因此

出现问题,就会将变量改为AtomicLong或者在常量下面进行移位来调节。但是在这之前都会用int,这样代码将会快一点而且简单一点。

wokerCount是一个被允许启动但是不允许停止的工作者线程数。这个值也许会短暂的与真实存活的线程数不同,比如当ThreadPool要求创建一个线程失败时,这时由存在

的线程来执行记录直到终止。

runState提供了主要的声明周期状态

RUNNING:接收新的任务并且处理排队中的任务                                                                             11100000000000000000000000000000

SHUTDOWN:不再接收新的任务,但是处理已经进入队列当中的任务                                                   00000000000000000000000000000000

STOP:不再接收新的任务,并且也不再处理队列中的任务,而且正在被执行的任务也会被中断(interrupt)       00100000000000000000000000000000

TIDYING(使整洁,有条理):所有的任务已经完成,workCount为0,线程变成TIDYING.                         01000000000000000000000000000000

TERMINAL:当terminated()方法完成时                                                                                     01100000000000000000000000000000

 

CAPACITY                                                                                                                           00011111111111111111111111111111

 

判断现在的工作者线程数:

private static int workerCountOf(int c)  { return c & CAPACITY; }

 

执行3部曲:

1、如果少于corePoolSize的线程数正在运行,那么新任务尝试启动新的线程。调用addWorker会检测runState和workerCount

2、如果一个任务能够成功入队,那么我们仍需要再次确认是否应该添加线程,因为在最后一次检查完成后,存在的某个线程已经死亡活着当进入这个方法后,

线程池被shutdown。于是我们需要冲洗检测状态。

3、如果我们不能够是任务进入队列,我们尝试新的线程。如果失败,我们知道我们已经shutdown或者已经饱和(saturated),于是我们拒绝任务。

 1  public void execute(Runnable command) {
 2         if (command == null)
 3             throw new NullPointerException();
 4        
 5         int c = ctl.get();
 6         if (workerCountOf(c) < corePoolSize) {
 7             if (addWorker(command, true))
 8                 return;
 9             c = ctl.get();
10         }
11         if (isRunning(c) && workQueue.offer(command)) {
12             int recheck = ctl.get();
13             if (! isRunning(recheck) && remove(command))
14                 reject(command);
15             else if (workerCountOf(recheck) == 0)
16                 addWorker(null, false);
17         }
18         else if (!addWorker(command, false))
19             reject(command);
20     }

 

判断运行状态:

private static int runStateOf(int c)     { return c & ~CAPACITY; }

 1  private boolean addWorker(Runnable firstTask, boolean core) {
 2         retry:
 3         for (;;) {
 4             int c = ctl.get();//得到运行状态和线程数的控制符
 5             int rs = runStateOf(c);//用整数的高3位来呈现5种运行状态
 6 
 7             // 在必要是检查队列是否为空
 8             if (rs >= SHUTDOWN &&//如果此时处于关闭、完成或者
 9                 ! (rs == SHUTDOWN &&//所加入的任务为空,那么就不入
10                    firstTask == null &&//队列
11                    ! workQueue.isEmpty()))
12                 return false;
13 
14             for (;;) {
15                 int wc = workerCountOf(c);//得到工作者线程数
16 /*如果此时工作者线程数已经超过了最大容量或者是超过了核心容器的线程数,那么就不能再如队列了。已经饱和。*/
17                 if (wc >= CAPACITY ||
18                     wc >= (core ? corePoolSize : maximumPoolSize))
19                     return false;
20                 if (compareAndIncrementWorkerCount(c))
21                     break retry;
22                 c = ctl.get();  // Re-read ctl
23                 if (runStateOf(c) != rs)
24                     continue retry;
25                 // else CAS failed due to workerCount change; retry inner loop
26             }
27         }
28 
29         boolean workerStarted = false;
30         boolean workerAdded = false;
31         Worker w = null;
32         try {
33             final ReentrantLock mainLock = this.mainLock;
34             w = new Worker(firstTask);
35             final Thread t = w.thread;
36             if (t != null) {
37                 mainLock.lock();
38                 try {
39                     // Recheck while holding lock.
40                     // Back out on ThreadFactory failure or if
41                     // shut down before lock acquired.
42                     int c = ctl.get();
43                     int rs = runStateOf(c);
44 
45                     if (rs < SHUTDOWN ||
46                         (rs == SHUTDOWN && firstTask == null)) {
47                         if (t.isAlive()) // precheck that t is startable
48                             throw new IllegalThreadStateException();
49                         workers.add(w);
50                         int s = workers.size();
51                         if (s > largestPoolSize)
52                             largestPoolSize = s;
53                         workerAdded = true;
54                     }
55                 } finally {
56                     mainLock.unlock();
57                 }
58                 if (workerAdded) {
59                     t.start();
60                     workerStarted = true;
61                 }
62             }
63         } finally {
64             if (! workerStarted)
65                 addWorkerFailed(w);
66         }
67         return workerStarted;
68     }

 

posted on 2015-05-27 12:34  飞机说之代码也疯狂  阅读(478)  评论(0编辑  收藏  举报