如何实现线程池的暂停和恢复功能

很多时候我们需要暂停线程池,而不是shutdown线程池,暂停线程池可以为我们保存任务,稍后可以继续执行,从而避免不必要的开销。

这里我提供一种暂停线程池的方法;

首先拿到ThreadPoolExecutor.java源码,将其变为自己包内的私有类;

接下来修改线程池,

先在线程池类中添加一下方法和变量:

BlockingQueue<Runnable> pauseQueue=new ArrayBlockingQueue<>(1);//暂停时用来则塞线程的空任务队列
 
 


isPause=true;//暂停

public void pause(){//暂停线程池,但是仍然接受任务
    
    isPause=true;
    System.out.println("暂停了"+isPause+exit);
}
public void resume(){//恢复线程池,开始接着执行任务

    isPause=false;
    
    if (workQueue.isEmpty()) {
        return;
    }
    pauseQueue.offer(workQueue.poll());
}
然后修改以下方法:

private Runnable getTask() {
    boolean timedOut = false; // Did the last poll() time out?

    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            
            return null;
        }

        int wc = workerCountOf(c);

        if (isPause){
            try {
                
                return pauseQueue.take();

            } catch (InterruptedException e) {
                
               
            }
            
        }
        // Are workers subject to culling?
        
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 ||workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c)) {
                
                return null;

            }
            
            continue;
        }

        try {

            Runnable r = timed ?// TODO: 2017/5/14 keepAliveTime为空闲线程存活的时间
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :// TODO: 2017/5/14 在空闲线程关闭之前尝试取走队列头的任务,如果还没有任务则返回null
                    workQueue.take();// TODO: 2017/5/14 获取队列头的任务 然后 在从队列移除该任务;
            if (r != null) {
                
                return r;
            }
            timedOut = true;// TODO: 2017/5/14 如果取不到任务则循环重取,如果队列已空则在上面返回空,当返回空时代表所有任务已完成,那么工作机器人会关闭并销毁
            
        } catch (InterruptedException retry) {
            timedOut = false;
            
        }
    }
}
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    
    if (isPause) {
       if (!workQueue.offer(command))
          reject(command);
       return;
    }
/* * Proceed in 3 steps: * * 1. If fewer than corePoolSize threads are running, try to * start a new thread with the given command as its first * task. The call to addWorker atomically checks runState and * workerCount, and so prevents false alarms that would add * threads when it shouldn't, by returning false. * * 2. If a task can be successfully queued, then we still need * to double-check whether we should have added a thread * (because existing ones died since last checking) or that * the pool shut down since entry into this method. So we * recheck state and if necessary roll back the enqueuing if * stopped, or start a new thread if there are none. * * 3. If we cannot queue task, then we try to add a new * thread. If it fails, we know we are shut down or saturated * and so reject the task. */ int c = ctl .get(); if ( workerCountOf (c) < corePoolSize ) { if (addWorker( command, true )) return ; c = ctl .get(); } if ( isRunning (c) && workQueue .offer(command)) { int recheck = ctl .get(); if (! isRunning (recheck) && remove(command)) reject(command); else if ( workerCountOf (recheck) == 0 ) addWorker( null , false ); } else if (!addWorker( command, false )) reject(command);} OK,先在只要调用pause()和resume()方法就能实现暂停和恢复。

源码下载

猜你喜欢

转载自blog.csdn.net/a1053904672/article/details/72321016