首页 新闻 会员 周边

Java ThreadPoolExecutor的使用问题

0
悬赏园豆:200 [已关闭问题] 关闭于 2017-10-09 19:17

先上的简单封装的类

public class TaskExecutor {
    private static final int DEFAULT_TASK_QUEUE_LEN = 200;
    private static final long DEFAULT_KEEP_ALIVE_TIME = 10 * 1000;

    private BlockingQueue<Runnable> taskQueue;
    private ThreadPoolExecutor executor;

    private static TaskExecutor instance;

    public static TaskExecutor getInstance(){
        if(instance == null)
            instance = new TaskExecutor();
        return instance;
    }

    private TaskExecutor() {
        this.taskQueue = new ArrayBlockingQueue(DEFAULT_TASK_QUEUE_LEN);
    }

    public void setPoolSize(int poolSize){
        if(this.executor == null){
            this.executor = new ThreadPoolExecutor(poolSize,poolSize,DEFAULT_KEEP_ALIVE_TIME,TimeUnit.SECONDS,this.taskQueue);
        }else{
            this.executor.setCorePoolSize(poolSize);
            this.executor.setMaximumPoolSize(poolSize);
        }
    }

    public void execute(Runnable task) throws InterruptedException {
        while (taskQueue.remainingCapacity() <= 0) { Thread.sleep(1); }
        executor.execute(task);
    }

    public void waitQueueClean() throws InterruptedException {
        while(taskQueue.remainingCapacity() < DEFAULT_TASK_QUEUE_LEN){ Thread.sleep(1);}
    }
}

这个类简单的来说是用来添加多个任务,

CorePoolSize和MaximumPoolSize设置同样大小。添加任务是如果队列已满则等待直到队列有空闲。
现在碰到这样的情况,代码中在向线程池中添加任务时发现偶尔有任务没被执行,但一直找不到原因。求大神帮忙分析一下到底是什么问题。
调用代码如下

public class classA {

    private TaskExecutor task;

    public  classA(){
        this.task = TaskExecutor.getInstance();
    }

    public void run() throws InterruptedException {
        for(int i=0;i<10000;i++){
            this.task.setPoolSize(RandomNumber);
            for(int j=0;j<10000;j++){
                this.task.execute(new Runnable() {
                    @Override
                    public void run() {
                        //要执行的任务
                    }
                });
            }
        }
    }
}

感激不尽

龙卷风摧毁停车场!的主页 龙卷风摧毁停车场! | 菜鸟二级 | 园豆:210
提问于:2017-08-06 19:04
< >
分享
所有回答(1)
0

因为ThreadPoolExecutor在execute时是使用BlockingQueue的offer方法,其对象的派生类在实现这个方法时都是在offer失败后(队列已满)调用ThreadPoolExecutor的RejectedExecutionHandler

这里有两个方法:

1.实现自己的队列,在offer方法中阻塞住写入队列操作

2.使用ThreadPoolExecutor的重载构造函数传入一个自己实现的RejectedExecutionHandler,比如直接在rejectedExecution中起线程跑对应的runnable

Daniel Cai | 园豆:10424 (专家六级) | 2017-08-07 09:41

队列已满时我会 while循环直到队列中有空时才会execute的,所以应该不会调用RejectedExecutionHandler吧?

public void execute(Runnable task) throws InterruptedException {
        while (taskQueue.remainingCapacity() <= 0) { Thread.sleep(1); }
        executor.execute(task);
    }

 

@找回初心: 你这种线程不安全判断没意义。

支持(0) 反对(0) Daniel Cai | 园豆:10424 (专家六级) | 2017-08-07 11:35

@Daniel Cai: 所以应该怎么改呢。。

@找回初心: 不是给了你两种方案了么?

支持(0) 反对(0) Daniel Cai | 园豆:10424 (专家六级) | 2017-08-07 13:56

@Daniel Cai: 我是在主线程中循环添加任务到线程中,不是多线程添加任务,应该和线程不安全没关系吧?

@找回初心: 最后任务都会堆到queue中,而queue会被多个线程来进行消耗,你说这里安全么?

最简单的方式自己去实现queue,内部把offer方法换成其他queue的add方法(阻塞式)

支持(0) 反对(0) Daniel Cai | 园豆:10424 (专家六级) | 2017-08-07 14:38

@Daniel Cai: 那其实只要任务添加到Queue中,肯定会被执行的是吧?

public void execute(Runnable task) throws InterruptedException {
        while (taskQueue.remainingCapacity() <= 0) { Thread.sleep(1); }
        executor.execute(task);
    }

这段代码就算有多个线程在消费Queue,也不会影响主线程往里面添加任务吧?主要是现在不确定任务是否被加入到Queue中。

@找回初心: 是啊,因为blockingqueue在线程池中提供的就是offer方法,offer返回false了就被reject了。

支持(0) 反对(0) Daniel Cai | 园豆:10424 (专家六级) | 2017-08-07 15:00

@找回初心: 多个线程在消费,那么taskQueue.remainingCapacity()读取到的是在那一刻的数据,没有东西确保后面你真正的在execute(加到队列时)这个还是>0的。

支持(0) 反对(0) Daniel Cai | 园豆:10424 (专家六级) | 2017-08-07 15:01

@Daniel Cai: 但是只有这个方法可以添加任务,而且是在主线程中循环添加任务的,也不存在多线程添加任务。所以taskQueue.remainingCapacity()读到数据是什么,在executor.execute(task)时,只会更小,不会变大吧?

@找回初心: 是,刚回过头看了下你的调用代码。

其中有点我不知道会不会出问题,建议你先改下

for(int i=0;i<10000;i++){ this.task.setPoolSize(RandomNumber); for(int j=0;j<10000;j++){

中间这个setPoolSize的调用

支持(0) 反对(0) Daniel Cai | 园豆:10424 (专家六级) | 2017-08-07 15:18

@Daniel Cai: setPoolSize是业务需求,因为任务里有调用第三方接口的代码,对不同的一组循环要控制并发数量,所以要设置线程数量。如果线程中的任务在执行的话,设置线程数应该不会有其它影响的。现在就是不知道什么情况下会使任务丢失

清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册