java多线程系列16 线程池

当系统系统规模较小,我们可以不使用线程池。但是当系统到达一定规模,频繁的创建和销毁线程池会消耗很多资源。

合理利用线程池能够带来三个好处。

1降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

2提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。

3提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

 

下面演示下线程池的基本的使用

public class ThreadPoolExecutorTest {
	public static void main(String[] args) {
		ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,
				new LinkedBlockingQueue<Runnable>());

		Runnable runnable = null;
		for (int i = 0; i < 20; i++) {
			runnable = new Runnable() {
				@Override
				public void run() {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + " run");
				}
			};
			executor.execute(runnable);
		}
		executor.shutdown();
	}
}

  

Jdk默认了实现了4种线程池。
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,默认是60秒,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行

 

查看源码 都是调用

 

其本质是通过不同的参数初始化一个ThreadPoolExecutor对象,只是传递的参数不同罢了

具体参数解释如下:

corePoolSize 线程池中的核心线程数,

maximumPoolSize 线程池中允许的最大线程数

keepAliveTime 线程空闲时的存活时间,即当线程没有任务执行时,继续存活的时间

keepAliveTime的 单位 unit

workQueue

用来保存等待被执行的任务的阻塞队列,且任务必须实现Runable接口,在JDK中提供了如下阻塞队列:
ArrayBlockingQueue:基于数组的有界阻塞队列,按FIFO排序任务;
LinkedBlockingQuene:基于链表的无界阻塞队列,按FIFO排序任务,吞吐量通常要高于ArrayBlockingQuene
SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene
priorityBlockingQuene:具有优先级的无界阻塞队列;

handler

线程池的拒绝策略,当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务,线程池内置4种策略:
1AbortPolicy:直接抛出异常,默认策略;
2CallerRunsPolicy:用调用者所在的线程来执行任务;
3DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;
4DiscardPolicy:直接丢弃任务;
当然我们也可以根据应用场景实现RejectedExecutionHandler接口,自定义拒绝策略,

实际开发中,一般先记录日志 再开一个定时去处理

执行流程图如下

 

 

======================================================================

原理解析 

 

找到线程池核心的execute()方法 源代码如下 

 

 if (command == null)
            throw new NullPointerException();
//ctl是一个包装变量 包含了线程池的状态以及线程池中线程数
        int c = ctl.get();
        //workerCountOf 获取线程池的当前线程数
     if (workerCountOf(c) < corePoolSize) { // 【步骤1】
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
    if (isRunning(c) && workQueue.offer(command)) { // 【步骤2】
            int recheck = ctl.get();
          if (! isRunning(recheck) && remove(command))   //【步骤4】
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
     else if (!addWorker(command, false)) // 【步骤3】
            reject(command);
    }

 

  

具体的执行流程如下:
--> 如果线程数小于corePoolSize,则执行addWorker方法创建新的线程执行任务 并返回 ;否则执行步骤2;
--> 如果线程池处于RUNNING状态,并且任务成功放入阻塞队列中,则执行步骤4,否则执行 步骤3
--> 再次检查线程池的状态,如果线程池没有RUNNING,并且从阻塞队列中删除任务,则执行reject方法处理任务;
--> 执行addWorker方法创建新的线程执行任务,如果addWoker执行失败,则执行reject方法处理任务;

接下来我们看看addWorker方法

addWorker分为2部分

retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);
//通过自旋的方式,判断要添加的Worker是否是true,如果是的话,那么
//则判断当前的workerCount是否大于corePoolsize,否则则判断是否大于//maximumPoolSize,如果满足的话,说明workerCount超出了线程池大小,直//接返回false 如果没有超出就cas让workerCount+1 如果成功就跳出循环 失//败就继续进行状态的判断
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
--------第一部分完 
/*如果满足了的话,那么则创建一个新的Worker对象 满足状态就添加到works中 然后启动Worker中的线程开始执行任务*/
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    int rs = runStateOf(ctl.get());
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }
 

  

 

 

posted on 2017-06-20 18:01  一只小蜗牛12138  阅读(232)  评论(0编辑  收藏  举报

导航