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队列中时顺序取出,但是执行的时候却是乱序的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值