Java 线程池工作原理

Java 线程池工作原理


背景和目的:
1.假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。
如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。
2.如果每个任务到来都进行线程的创建,运行完成后再消毁线程,当任务请求非常多时,应用就有非常多的线程同时创建,
运行时就有非常多的线程进行切换,这种对系统资源的开销是非常大的。
3.除了创建和销毁线程的开销之外,活动的线程也消耗系统资源。在一个JVM 里创建太多的线程可能会导致系统由于过度
消耗内存而用完内存或“切换过度”。
4.线程池就是为了解决上述问题提出的解决方案。
5.Java中的ThreadPoolExecutor类是实现线程池的一个类。


线程池四个基本组成部分:
1、线程池管理器(ThreadPool):用于创建并管理线程池,包括创建线程池,销毁线程池,添加新任务;
2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务,工作线程是线程池进行创建和销毁的(无需人为创建);
3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;
4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。(任务就是自己按业务需求进行编写的(实现implements Runnable接口run)实例对象)


线程池工作原理:
1.应用启动时就进行若干个工作线程的初始化,并存入线程池中。这样工作线程(ThreadPoolExecutor中Worker)就创建了。
2.任务到达时,将任放到任务队列(ThreadPoolExecutor中workQueue)中。(如:threadPoolExecutor.execute(myTask);)
3.工作线程从任务队列中取出任务并运行任务接口进行任务的处理。
4.当任务队列中的任务非常多时,线程池管理器就会创建新的工作线程(ThreadPoolExecutor中Worker)放入线程池中,新的工作线程也进行任务的处理。
5.这样做就减少了应用中线程的个数,运行任务时没有进行线程的创建;线程个数减少,线程切换的系统开销也就减少了。
6.就是将任务就成一个实例(实现implements Runnable接口run),并创建指定个线程(ThreadPoolExecutor中Worker)不断地从任务队列(ThreadPoolExecutor中workQueue)
中取出任务实例,并运行实例中的run方法。



Java中的ThreadPoolExecutor类
public class ThreadPoolExecutor extends AbstractExecutorService {
    .....
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue);

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

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

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


1.corePoolSize:核心池的大小,(主工作线程的个数)
2.maximumPoolSize:线程池最大线程数(比corePoolSize大的都是临时的,需要的时候才创建放到线程池中)
3.keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。
4.unit:参数keepAliveTime的时间单位,
TimeUnit.DAYS;               //天
TimeUnit.HOURS;             //小时
TimeUnit.MINUTES;           //分钟
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //纳秒

5.workQueue:一个阻塞队列,用来存储等待执行的任务,
6.threadFactory:线程工厂,主要用来创建线程;
7.handler:表示当拒绝处理任务时的策略,有以下四种取值:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务




ThreadPoolExecutor类中其他的一些比较重要成员变量
private final BlockingQueue<Runnable> workQueue;              //任务缓存队列,用来存放等待执行的任务
private final ReentrantLock mainLock = new ReentrantLock();   //线程池的主要状态锁,对线程池状态(比如线程池大小
                                                              //、runState等)的改变都要使用这个锁
private final HashSet<Worker> workers = new HashSet<Worker>();  //用来存放工作集

private volatile long  keepAliveTime;    //线程存货时间
private volatile boolean allowCoreThreadTimeOut;   //是否允许为核心线程设置存活时间
private volatile int   corePoolSize;     //核心池的大小(即线程池中的线程数目大于这个参数时,提交的任务会被放进任务缓存队列)
private volatile int   maximumPoolSize;   //线程池最大能容忍的线程数

private volatile int   poolSize;       //线程池中当前的线程数

private volatile RejectedExecutionHandler handler; //任务拒绝策略

private volatile ThreadFactory threadFactory;   //线程工厂,用来创建线程

private int largestPoolSize;   //用来记录线程池中曾经出现过的最大线程数

private long completedTaskCount;   //用来记录已经执行完毕的任务个数




任务的提交
execute()	//这个方法可以向线程池提交一个任务,交由线程池去执行。
submit()	//这个方法也是用来向线程池提交任务的,但是它和execute()方法不同,它能够返回任务执行的结果
shutdown()	//线程池处于SHUTDOWN状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕
shutdownNow()	//线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务



例子:
package ThreadPool;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPool {
	public static void main(String[] args) {
		ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 10, 200, TimeUnit.MILLISECONDS,
				new LinkedBlockingQueue(100));

		for (int j = 0; j < 16; j++) {
			for (int i = 0; i < 16; i++) {
				MyTask myTask = new MyTask(j*100+i);
				threadPoolExecutor.execute(myTask);
				System.out.println("线程池中线程数目:" + threadPoolExecutor.getPoolSize() + ",队列中等待执行的任务数目:" + threadPoolExecutor.getQueue().size()
						+ ",已执行完的任务数目:" + threadPoolExecutor.getCompletedTaskCount());
			}
		}
		threadPoolExecutor.shutdown();
	}
}


package ThreadPool;

class MyTask implements Runnable { //实现接口Runnable接口run,
	private int taskNum;

	public MyTask(int num) {
		this.taskNum = num;
	}

	public void run() {//接口run,你的任务逻辑在这里实现
		System.out.println("正在执行task " + this.taskNum);
		System.out.println("task " + taskNum + "执行完毕");
	}
}



spring线程池(TaskExecutor)
参考原文: http://lishaorui.iteye.com/blog/1051823


参考原文: http://www.cnblogs.com/dolphin0520/p/3932921.html
参考原文: http://www.blogjava.net/stevenjohn/archive/2011/12/12/366161.html
参考原文: http://wenku.baidu.com/link?url=GoqD2-ouxAVhPVfs20rqelSjDPs8IPHq6dQanWuJpca8Em9yxiGMLoHS2-1Pyq8tec9Z25z8FiqDJBhWhKUSAd82YEW4Bu7wio7JTHUp3YG

猜你喜欢

转载自huangyongxing310.iteye.com/blog/2327098