并发编程:Executors(二、自定义线程池)

        前面介绍到,Executor的线程池工厂通过ThreadPoolExecutor来构建带有特定功能的线程池,同样,也可以使用ThreadPoolExecutor来构建自定义线程池。

        通过ThreadPoolExecutor构建自定义线程池比较关键的是其构造函数中所传入的队列类型。

        使用有界队列时:若有新的任务需要执行时,如果线程池实际线程数小于corePoolSize,则优先创建线程,若大于corePoolSize,则会将任务加入队列,若队列已满,则在总线程数不大于maximumPoolSize的前提下创建新的线程,若线程数大于maximumPoolSize,则执行拒绝策略或其他自定义处理策略。下面举一段小例子:

类:有界队列的线程池

	public static void main(String[] args) {
		//自定义线程池:核心线程数1、最大线程数2、时间组合:数量6、时间组合:单位秒、任务队列(有界队列):数量3、自定义拒绝策略
		ThreadPoolExecutor myPool = new ThreadPoolExecutor(1,2,6,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(3),new 自定义拒绝策略());
		//任务
		MyTask task1 = new MyTask(1,"张三提交的任务:吃饭");
		MyTask task2 = new MyTask(2,"李四提交的任务:睡觉");
		MyTask task3 = new MyTask(3,"王五提交的任务:写BUG");
		MyTask task4 = new MyTask(4,"赵六提交的任务:钱七,你今天带药了吗?");
		MyTask task5 = new MyTask(5,"钱七提交的任务:今天我带的是速效救心丸!");
		MyTask task6 = new MyTask(6,"吕八提交的任务:我是秀才,我要去找芙妹!");
		//线程池执行任务
		myPool.execute(task1);
		myPool.execute(task2);
		myPool.execute(task3);
		myPool.execute(task4);
		myPool.execute(task5);
		//myPool.execute(task6);
		//优雅关机
		myPool.shutdown();
                //myPool.shutdownNow();
	}

运行效果如图:

MyTask [taskId=1, taskName=张三提交的任务:吃饭]
MyTask [taskId=5, taskName=钱七提交的任务:今天我带的是速效救心丸!]
MyTask [taskId=2, taskName=李四提交的任务:睡觉]
MyTask [taskId=3, taskName=王五提交的任务:写BUG]
MyTask [taskId=4, taskName=赵六提交的任务:钱七,你今天带药了吗?]

        显然,任务12345的执行顺序为:1先到且立即执行,2、3、4任务到达后存放进ArrayBlockingQueue队列,任务5到达后线程池开启最大线程数(2),且立即执行了任务5,之后再依次执行了ArrayBlockingQueue队列里边的任务2、3、4。

将任务六放行,运行结果如图:

MyTask [taskId=1, taskName=张三提交的任务:吃饭]
嘀 ___好人卡
MyTask [taskId=5, taskName=钱七提交的任务:今天我带的是速效救心丸!]
MyTask [taskId=2, taskName=李四提交的任务:睡觉]
MyTask [taskId=3, taskName=王五提交的任务:写BUG]
MyTask [taskId=4, taskName=赵六提交的任务:钱七,你今天带药了吗?]

       显然,在任务5到达后(此时任务1正在执行中,任务2、3、4已经放入队列),任务5被立即执行,此时任务6到达,但此时线程池线程个数已经达到最大且任务队列也已经满了,所以执行了JDK提供的默认的拒绝策略,任务6不被执行,而在任务队列中的任务2、3、4则继续依次执行。

        使用无界队列(LinkedBlockingQueue)时:与有界队列相比,除非系统资源耗尽,否则不会出现任务入队失败的情况。当有新任务到来时,系统的线程数小于corePoolSize时,则新建线程以执行任务,当线程数达到核心线程数个数之后就不会再增加线程,如果此时有新的任务到达,则将任务放到任务队列里边。当任务创建和处理的速度差异很大时,任务队列就会持续增加,知道系统内存被耗尽。下面举一段小例子:

public class 无界队列的线程池 implements Runnable {
	private static AtomicInteger count = new AtomicInteger(0);
	@Override
	public void run() {
		try {
			System.err.println("这是任务"+count.incrementAndGet());
			Thread.sleep(2*1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) throws Exception {
		BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
		ExecutorService executor = new ThreadPoolExecutor(5,10,120l,TimeUnit.SECONDS,queue);
		for(int index = 0;index<50;index++) {
			executor.execute(new 无界队列的线程池());
		}
		
		int size = queue.size();
		while(size > 0 ) {
			Thread.sleep(1*1000);
			System.err.println("queue size is :"+size);
			size = queue.size();
		}
	}

}

        JDK提供的拒绝策略有:AbortPolicy(直接抛出一个异常,阻止系统正常工作)、CallerRunsPolicy(只要线程池未关闭,直接在调用者线程中运行当前被丢弃的任务)、DiscardOldestPolicy(丢弃最老的一个请求,尝试再次提交当前任务)、DiscardPolicy(丢弃无法处理的任务,不给予任何处理)。

        自定义拒绝策略可以通过实现RejectedExecutionHandler接口来构建。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值