Java 线程池 Executors

 

java线程池灵活多变,很容易让人懵逼,现在我们先看下线程池有哪些分类

 

ExecutorService真正的线程池接口。
ScheduledExecutorService能和Timer/TimerTask类似,解决那些需要任务重复执行的问题。
ThreadPoolExecutorExecutorService的默认实现
ScheduledThreadPoolExecutor继承ThreadPoolExecutor的ScheduledExecutorService接口实现,周期性任务调度的类实现。

 

Java通过Executors提供四种线程池,它的子类ExecutorService,ScheduledExecutorService可以直接使用这些池,这些线程池只不过都是ThreadPoolExecutor的各种定制,分别为:

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

接下来看下ExecutorService,ScheduledExecutorService的使用,注释也很重要

/**
 * ExecutorService和ScheduledExecutorService
 * 
 * 调用以下三个静态方法都是返回一个 ExecutorService
 * Executors.newCachedThreadPool(); 
 * Executors.newFixedThreadPool(10);
 * Executors.newSingleThreadExecutor()
 * 
 * ScheduledExecutorService 继承 ExecutorService
 * 只有调用Executors.newScheduledThreadPool(1);方法才会返回ScheduledExecutorService
 * ScheduledExecutorService(即:newScheduledThreadPool(int))用于执行定时任务和循环任务
 * scheduleAtFixedRate:按照上一次任务的发起时间计算下一次任务的开始时间
 * scheduleWithFixedDelay: 以上一次任务的结束时间计算下一次任务的开始时间
 * scheduledExecutorService.shutdown() 关闭线程池,不再接收提交的任务,scheduledExecutorService不可再使用; 
 * ScheduledFuture<?>.cancel(true)只是关闭某一个线程任务,线程池不会受影响,线程池不会关闭,会等待Runnable来执行
 */
private static void executorServiceTest() {
	ExecutorService executorService;
	executorService=Executors.newCachedThreadPool();
	executorService=Executors.newFixedThreadPool(10);
	executorService=Executors.newSingleThreadExecutor();
	
	ScheduledExecutorService scheduledExecutorService=Executors.newScheduledThreadPool(1);
	if(state==null||state.isDone()) {
		state=scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
			@Override
			public void run() {
				Thread th=Thread.currentThread();
				System.out.println("hello world******"+th.getName()+"***"+th.getId());
				count++;
				if(count>=3) {
					state.cancel(true);
					count=0;
					System.out.println("*********OVER*********");
				}
				executorServiceTest();
			}
		}, 0, 2, TimeUnit.SECONDS);
	}
}

下来看下ThreadPoolExecutor

/**
 * 4种构造方法
 * ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) 
 *
 * ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory)
 *
 * ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler)
 *
 * ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
 * 
 * 构造方法的参数:
 * corePoolSize:      核心线程数,默认情况下核心线程会一直存活,即使处于闲置状态也不会受存keepAliveTime限制。除非将allowCoreThreadTimeOut设置为true。
 * maximumPoolSize:线程池所能容纳的最大线程数。超过这个数的线程将被阻塞。当任务队列为没有设置大小的LinkedBlockingDeque时,这个值无效。
 * keepAliveTime:	非核心线程的闲置超时时间,超过这个时间就会被回收。
 * unit:			指定keepAliveTime的单位,如TimeUnit.SECONDS。当将allowCoreThreadTimeOut设置为true时对corePoolSize生效。
 * workQueue:		线程池中的任务队列.    常用的有三种队列,SynchronousQueue,LinkedBlockingDeque,ArrayBlockingQueue
 * threadFactory:	线程工厂,提供创建新线程的功能。ThreadFactory是一个接口,只有一个方法,通过线程工厂可以对线程的一些属性进行定制。
 * RejectedExecutionHandler:	RejectedExecutionHandler也是一个接口,只有一个方法,当线程池中的资源已经全部使用,添加新线程被拒绝时,会调用RejectedExecutionHandler的rejectedExecution方法。
 *
 * 线程池规则:
 * 线程池的线程执行规则跟任务队列有很大的关系。
 * 	下面都假设任务队列没有大小限制:
 * 		1.如果线程数量<=核心线程数量,那么直接启动一个核心线程来执行任务,不会放入队列中
 * 		2.如果线程数量>核心线程数,但<=最大线程数,并且任务队列是LinkedBlockingDeque的时候,超过核心线程数量的任务会放在任务队列中排队。
 * 		3.如果线程数量>核心线程数,但<=最大线程数,并且任务队列是SynchronousQueue的时候,线程池会创建新线程执行任务,这些任务也不会被放在任务队列中。这些线程属于非核心线程,在任务完成后,闲置时间达到了超时时间就会被清除
 * 		4.如果线程数量>核心线程数,并且>最大线程数,当任务队列是LinkedBlockingDeque,会将超过核心线程的任务放在任务队列中排队。也就是当任务队列是LinkedBlockingDeque并且没有大小限制时,线程池的最大线程数设置是无效的,他的线程数最多不会超过核心线程数。
 * 		5.如果线程数量>核心线程数,并且>最大线程数,当任务队列是SynchronousQueue的时候,会因为线程池拒绝添加任务而抛出异常。
 * 		6.ArrayBlockingQueue 阻塞队列。当核心线程都被占用,且阻塞队列已满的情况下,才会开启额外线程
 * 	任务队列大小有限时
 * 		1.当LinkedBlockingDeque塞满时,新增的任务会直接创建新线程来执行,当创建的线程数量超过最大线程数量时会抛异常。
 * 		2.SynchronousQueue没有数量限制。因为他根本不保持这些任务,而是直接交给线程池去执行。当任务数量超过最大线程数时会直接抛异常。
 *
 */
private void threadPoolExecutorTest() {
	ThreadPoolExecutor executor = new ThreadPoolExecutor(6, 10, 5, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
	executor.execute(new Runnable() {
		@Override
		public void run() {
			// TODO Auto-generated method stub
		}
	});
}

补一张图片,让大家熟悉下各类之间的关系,其中红色的线和框表示接口和接口继承,绿色的线和框表示实现类,浅蓝色的线和框表示子实现类的 子类和父类 之间的继承关系

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

baoolong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值