线程池

线程池

       线程池是一种线程容器,在线程池中,有一些活跃线程,当需要线程的时候可以从线程池中获取一个线程,当完成工作后,可以将线程放回到线程池中,方便其他人使用。线程池避免了每次需要线程的时候都要创建线程和销毁线程,节省了时间和空间开销,提升了性能。

       JDK内置支持线程池,在concurrent并发包里包含了线程池的相关类。Executors类是线程池工厂,通过Executors可以获得特定功能的线程池。

       Executors的主要工厂方法如下:

public static ExecutorService newFixedThreadPool (int nThread);

public static ExecutorService newSingleThreadExecutor ();

public static ExecutorService newCachedThreadPool ();

public static ScheduledExecutorService newSingleThreadSchuduledExecutor ();

public static ScheduledExecutorService newScheduledThreadPool (int corePoolSize);

       这些方法会返回特定功能的线程池:

       •newFixedThreadPool()方法,返回一个固定线程数量的线程池。该线程池中的数量始终不变。当有一个新的任务提交时,线程池中如果有空闲的线程,则立即执行。若没有,则新的任务会被放在一个任务队列中,待有线程空闲时,便处理任务队列中的任务。

       •newSingleThreadExecutor()方法,返回一个只有一个线程的线程池。若多于一个任务被提交到该线程池,则任务被保存在一个任务队列中,待线程空闲,按先进先出的顺序执行队列中的任务。

       •newCachedThreadPool()方法,返回一个可根据实际情况调整线程数量的线程池。线程池中线程的数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有线程都在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务完成之后,进入线程池进行复用。

      •newSingleThreadSchuduledExecutor()方法,返回一个ScheduledExecutorService对象,线程池大小为1ScheduledExecutorService在ExecutorService接口基础上扩展了功能,可以在给定时间执行某个任务,如在固定的时间后执行或者周期性的执行某个任务。

       •newScheduledThreadPool(int corePoolSize)方法,也返回一个ScheduledExecutorService对象,但是线程池可以指定线程数量。

应用示例:

public class ThreadPoolDemo implements Runnable{
	public void run(){
		System.out.println("I am "+Thread.currentThread().getName());
	}

	public static void main(String[] args) {
		ThreadPoolDemo demo=new ThreadPoolDemo ();
		ExecutorService exe=Executors.newFixedThreadPool (3);
//		ExecutorService exe=Executors.newSingleThreadExecutor ();
//		ExecutorService exe=Executors.newCachedThreadPool ();
		for(int i=0; i<6; i++){
			exe.execute (demo);
//			exe.submit (demo);//与上一句有些许差别
		}
	}
}

1、核心线程池的内部实现

       对于几个核心的线程池,newFixedThreadPool()、newSingleThreadExecutor()和newCachedThreadPool(),它们的内部实现都使用了ThreadPoolExecutor。

       三个线程池的实现方式:

从上述代码可以看出,这三个核心线程池都是ThreadPoolExecutor类的封装。下面看一下ThreadPoolExecutor的构造函数:

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

构造函数的各个参数含义如下:

       corePoolSize:指定了线程池中线程的数量。

       maximumPoolSize:指定了线程池中线程的最大数量。

       keepAliveTime:当线程池中线程数量超过corePoolSize时,多余的空闲线程的存活时间。即,超过corePoolSize的线程,在多长时间后会被销毁。

       unit:keepAliveTime的时间单位。

       workQueue:任务队列,存放被提交但尚未被执行的任务。

       threadFactory:线程工厂,用于创建线程,一般使用默认。

       handler:拒绝策略,当任务太多来不及处理,如何拒绝任务。

       workQueue参数:

       其是一个BlockingQueue接口的对象,仅用于存放Runnable对象。ThreadPoolExecutor的构造函数中可以使用如下几种BlockingQueue:

       •直接提交的队列:SynchronousQueue。SynchronousQueue没有容量,每一个插入操作都要等待一个相应的删除操作,每一个删除操作都要等待对应的插入操作。使用Synchronous,并不会真正保存任务,其总是将新任务提交给线程执行,如果没有空闲的线程,则新建一个线程,如果线程数量已经达到最大值,则执行拒绝策略。

       •有界任务队列:ArrayBlockingQueue,需要指定该队列的最大容量。若使用有界的任务队列,当有新的任务需要执行,如果线程池的实际线程个数小于corePoolSize,则会优先创建线程,若大于corePoolSize,则会将新任务添加到任务等待队列。若队列已满,无法加入,若总线程数小于maximumPoolSize,则创建新线程执行任务。若大于maximumPoolSize,则执行拒绝策略。

       •无界任务队列:LinkedBlockingQueue。与有界任务队列相比,除非系统资源耗尽,否则无界任务队列不存在入队失败。若使用无界任务队列,当有新的任务到来,如果线程数量小于corePoolSize,则创建新的线程执行任务,当线程数达到corePoolSize时,就不会再增加。若后续还有新任务,直接加入到队列中。

      •优先任务队列:PriorityBlockingQueue,其是带有执行优先级的队列,是一个特殊的无界队列。ArrayBlockingQueue和LinkedBlockingQueue都是按照先进先出处理任务的。而PriorityBlockingQueue是根据任务自身的优先级选择任务执行。

       ThreadPoolExecutor调度策略:

handler:拒绝策略

       拒绝策略是系统超负荷运行时的补救措施,通常是由于压力太大而引起的,也就是线程池中的线程已经用完了,无法继续为新任务服务,同时,等待队列中也已经排满了,再也塞不下新任务。这时就需要拒绝策略处理这个问题。

       JDK内置四种拒绝策略:

       AbortPolicy策略:该策略会直接抛出异常,阻止系统正常工作。

       CallerRunsPolicy策略:只要线程池未关闭,该策略直接在调用者线程中运行任务,不会真正丢弃任务,但会导致提交任务的线程性能急剧下降。

       DiscardOldestPolicy策略:丢弃一个最老的请求,并尝试再次提交该任务。

       •DiscardPolicy策略:默默丢弃无法处理的任务,不作任何处理。

 

参考:《实战Java高并发程序设计》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值