ThreadPoolExecutor的4种拒绝策略(TODO未完成)

ThreadPoolExecutor的4种拒绝策略

问题场景


当加入的任务数量超过一定数目(maximumPoolSize + BlockingQueue 队列长度),默认情况下会抛出异常。这种情况会造成某些采集、转换错误、遗漏,不符合预期。

期望的结果是,分页循环遍历基础数据,为每一条数据创建采集转换任务依次加入任务队列,当任务队列满主线程阻塞等待或者减缓创建和加入的速度。

策略概念


1. 策略1:ThreadPoolExecutor.AbortPolicy(),中止策略,将抛出 RejectedExecutionException。(默认情况)

在任务不能再提交的时候,抛出异常,及时反馈程序运行状态。

Notes:In the default ThreadPoolExecutor.AbortPolicy, the handler throws a runtime RejectedExecutionException upon rejection

使用场景:当系统不能承载更大的并发量的时候,能够及时的通过异常发现。

2. 策略2:ThreadPoolExecutor.CallerRunsPolicy()

CallerRunsPolicy直译过来是调用者执行策略。

Notes:A handler for rejected tasks that runs the rejected task directly in the calling thread of the execute method, unless the executor has been shut down, in which case the task is discarded.

使用场景:不是很关键的业务(容错性高),推荐使用此拒绝策略

3.策略3:ThreadPoolExecutor.DiscardOldestPolicy()

FIFO(加入队伍中时间最久)任务策略。

Notes:In ThreadPoolExecutor.DiscardOldestPolicy, if the executor is not shut down, the task at the head of the work queue is dropped, and then execution is retried (which can fail again, causing this to be repeated.

使用场景:数据采集(允许抛弃时间最久的任务)

4. 策略4:ThreadPoolExecutor.DiscardPolicy()

Notes:In ThreadPoolExecutor.DiscardPolicy, a task that cannot be executed is simply dropped.

使用场景:队列满了丢任务不异常(这是多大的心啊,暂时不知道为何设计一个不抛出异常的方式)

策略2的应用——写的一个类似于everything的小程序中FileScanner类的实现


package task;

import java.io.File;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

@SuppressWarnings("ALL")
public class FileScanner {
    //1.核心线程数:始终运行的线程数量
    //2.最大线程数:有新任务,并且当前运行线程数小于最大线程数,会创建新的线程来处理任务(正式+临时)
    //3-4.超过3这个数量,4这个时间单位,2-1(最大线程数-核心线程数)这些线程(临时)就会关闭
    //5.工作的阻塞队列
    //6.如果超出工作队列的常务,任务要处理的方式(4种策略)
    private static volatile AtomicInteger count= new AtomicInteger();

    private Object lock=new Object();

    private Semaphore semaphore=new Semaphore(0);//acquire()阻塞等待一定数量的许可

    private ThreadPoolExecutor pool=new ThreadPoolExecutor(
            3,3,0, TimeUnit.MICROSECONDS,
            new LinkedBlockingQueue<>(),new ThreadPoolExecutor.CallerRunsPolicy());

    private ScanCallback callback;

    public FileScanner(ScanCallback callback) {
        this.callback=callback;
    }

//多线程的任务等待
//最开始,不知道有多少子文件夹,不知道应该启动多少个线程
    public void scan(String path) {
       //递归使用线程池
        count.incrementAndGet();
        doScan(new File(path));
    }
    private void doScan(File dir){
        callback.callback(dir);
        pool.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    File[] children = dir.listFiles();//下一级文件和文件夹
                    if (children != null) {
                        for (File child : children) {
                            if (child.isDirectory()) {
                                count.incrementAndGet();//启动子目录文件夹
                                doScan(child);
                            }
                        }
                    }
                }
                finally{
                    int r = count.decrementAndGet();
                    if (r == 0) {
                        semaphore.release();
                    }
                }
            }
        });
    }

    public void waitFinish() throws InterruptedException {
        semaphore.acquire();
    }
   

}
发布了112 篇原创文章 · 获赞 171 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43914278/article/details/104321675
今日推荐