ThreadPoolExecutor的使用(二)

本文介绍了如何使用ThreadFactory和UncaughtExceptionHandle处理线程池异常,以及设置自定义的拒绝策略。通过实例展示了prestartCoreThread、prestartAllCoreThreads等方法的功能,并详细解释了ThreadPoolExecutor的几种拒绝策略,如AbortPolicy、CallerRunsPolicy等。同时,讨论了beforeExecute和afterExecute方法在监控线程池执行情况中的作用,并提及了remove方法的使用以及线程池相关属性的获取方法。

1. ThreadFactory+executor+UncaughtExceptionHandle处理异常
对线程池的创建中可以使用自定义的ThreadFactory,使用自定义的ThreadFactory时如果出现异常完全可以自定义处理。

MyThreadFactory 自定义的线程工厂,包含自定义的异常处理

import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.ThreadFactory;

public class MyThreadFactory implements ThreadFactory{

	@Override
	public Thread newThread(Runnable r) {
		Thread thread = new Thread(r);
		thread.setName("定制线程池大小的自定义线程工厂 ");
		thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
			
			@Override
			public void uncaughtException(Thread t, Throwable e) {
				System.out.println("自定义线程处理异常开始 "+ thread.getName());
				e.printStackTrace();
			}
		});
		return thread;
	}

}

测试代码

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

public class MyThreadPoolExecutor {
	public static void main(String[] args) throws InterruptedException {
		ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 5, TimeUnit.SECONDS,
				new LinkedBlockingDeque<Runnable>(),new MyThreadFactory());
		executor.execute(()->{
			System.out.println(Thread.currentThread().getName()+" begin "+System.currentTimeMillis());
			 String s=null;
			 s.indexOf("a");
			System.out.println(Thread.currentThread().getName()+" end "+System.currentTimeMillis());
		});
		 
	}
}

测试结果:
定制线程池大小的自定义线程工厂 begin 1596344223105
自定义线程处理异常开始 定制线程池大小的自定义线程工厂
java.lang.NullPointerException
at thread.api.executor.MyThreadPoolExecutor.lambda0(MyThreadPoolExecutor.java:14)atjava.util.concurrent.ThreadPoolExecutor.runWorker(UnknownSource)atjava.util.concurrent.ThreadPoolExecutor0(MyThreadPoolExecutor.java:14) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor0(MyThreadPoolExecutor.java:14)atjava.util.concurrent.ThreadPoolExecutor.runWorker(UnknownSource)atjava.util.concurrent.ThreadPoolExecutorWorker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

2. setRejectedExecutionHandler
用于设置线程池的拒绝策略,也可以设置成我们自定义的拒绝策略,构造方法中也是可以设置的,传入的拒绝策略为NULL会抛出异常。

自定义的拒绝策略

import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

public class MyRejectedExcutionHandler implements RejectedExecutionHandler{

	@Override
	public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
		System.out.println("自定义拒接策略被执行");
		
	}

}

测试代码

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

public class MyThreadPoolExecutor {
	public static void main(String[] args) throws InterruptedException {
		ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 5, TimeUnit.SECONDS,
				new LinkedBlockingDeque<Runnable>(1),new MyThreadFactory());
		executor.setRejectedExecutionHandler(new MyRejectedExcutionHandler());
		for(int i = 0;i<4;i++) {
			executor.execute(()->{
				System.out.println(Thread.currentThread().getName()+" begin "+System.currentTimeMillis());
				 try {
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+" end "+System.currentTimeMillis());
			});
		}
		 
	}
}

测试结果:
定制线程池大小的自定义线程工厂 begin 1596348608702
定制线程池大小的自定义线程工厂 begin 1596348608702
自定义拒接策略被执行
定制线程池大小的自定义线程工厂 end 1596348609703
定制线程池大小的自定义线程工厂 end 1596348609703
定制线程池大小的自定义线程工厂 begin 1596348609703
定制线程池大小的自定义线程工厂 end 1596348610703

3. prestartCoreThread 每次调用就会创建一个核心线程,返回是否启动成功

  public boolean prestartCoreThread() {
        return workerCountOf(ctl.get()) < corePoolSize &&
            addWorker(null, true);
    }

4. prestartAllCoreThreads 启动全部核心线程,返回启动核心线程数

    public int prestartAllCoreThreads() {
        int n = 0;
        while (addWorker(null, true))
            ++n;
        return n;
    }

5. getCompletedTaskCount 取得已经执行完的任务数

   public long getCompletedTaskCount() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            long n = completedTaskCount;
            for (Worker w : workers)
                n += w.completedTasks;
            return n;
        } finally {
            mainLock.unlock();
        }
    }

6. ThreadPoolExecutor的拒绝策略

  1. AbortPolicy :当任务添加到线程池中被拒绝时,抛出RejectedExcctionException异常,ThreadPoolExecutor默认的拒绝策略。
  2. CallerRunsPolicy:当任务添加到线程池中被拒绝时,会使用调用线程池的线程对象处理被拒绝的任务。
  3. DiscardOldestPolicy:当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最久的未处理任务,然后将拒绝任务添加到队列中。
  4. DiscardPolicy:当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务。

7. beforeExecute和afterExecute
重写ThreadPoolExecutor的这两个方法可以对线程池中的对象进行监控,了解当前线程池中谁准备执行,谁执行完毕。

MyRunnable

import java.util.concurrent.TimeUnit;

public class MyRunnable implements Runnable{
	
	private String uaseName;
	
	public MyRunnable(String uaseName) {
		super();
		this.uaseName = uaseName;
	}

	public String getUaseName() {
		return uaseName;
	}

	public void setUaseName(String uaseName) {
		this.uaseName = uaseName;
	}

	@Override
	public void run() {
		 System.out.println("线程 "+uaseName+" 开始执行");
		try {
			TimeUnit.SECONDS.sleep(4);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("线程 "+uaseName+" 执行完成");
	}

}

MyThreadPoolExecutor

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

public class MyThreadPoolExecutor extends ThreadPoolExecutor {

	public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
			BlockingQueue<Runnable> workQueue) {
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
		// TODO Auto-generated constructor stub
	}
	
	@Override
	protected void afterExecute(Runnable r, Throwable t) { 
		super.afterExecute(r, t);
		System.out.println(((MyRunnable) r).getUaseName() +"执行完毕");
	}
	
	@Override
	protected void beforeExecute(Thread t, Runnable r){ 
		super.beforeExecute(t,r);
		System.out.println(((MyRunnable) r).getUaseName() +"开始执行");
	}	 
}

测试代码

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;

public class ThreadPoolExecutorTest {

	public static void main(String[] args) {
		MyThreadPoolExecutor my = new MyThreadPoolExecutor(2,2,5,TimeUnit.SECONDS,
				new LinkedBlockingDeque<Runnable>());
		my.execute(new MyRunnable("A1"));
		my.execute(new MyRunnable("A2"));
		my.execute(new MyRunnable("A3"));
	}

}

测试结果:
A1开始执行
A2开始执行
线程 A2 开始执行
线程 A1 开始执行
线程 A2 执行完成
A2执行完毕
A3开始执行
线程 A3 开始执行
线程 A1 执行完成
A1执行完毕
线程 A3 执行完成
A3执行完毕

8. remove方法
可以删除尚未执行的Runnable任务,注意只能删除execute(Runnable)方式提交的任务,submit(Runnable)提交的是不能删除的。

9. 多个getXxx方法说明
1. getActiveCount 获得当前线程池中正在执行任务的线程数。
2. getPoolSize 获得当前线程池里面有多少个线程,包括执行任务的和休眠状态的线程。
3. getCompletedTaskCount 获取线程池中已经执行完的任务数。
4. getCorePoolSize 获取核心线程数,就是构造时传入的corePoolSize。
5. getMaximumPoolSize 获取最大线程数,就是构造时传入的maximumPoolSize。
6. getTaskCount 获取发给线程池的任务总数。

10. Runnable接口在 ThreadPoolExecutor队列中时顺序取出,但是执行的时候却是乱序的。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值