我已经实现了一个单例(管理器)来管理一些相关的任务,在这个管理器里我正在使用一个执行器来同时处理10个任务,我使用的是无限制的linkedBlockingQueue,而且到目前为止工作正常,但是现在我需要为执行程序队列设置一个限制,因为我有很多任务(数十万个任务),而且我不想把它们全部放在我的队列中导致我出现性能问题,所以我做了什么:
这是我的执行官:
public class MyThreadPoolExecutor extends ThreadPoolExecutor {
public MyThreadPoolExecutor(int corePoolSize, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, corePoolSize + 5, 500, TimeUnit.MILLISECONDS, workQueue);
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
//Do something to my task
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if(t != null) {
//
} else {
//Do something to my task
}
}
}
这是我的经理:
public final class MyManager {
private static MyManager manager = new MyManager();
public static final int queueMaxSize = 100;
private BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(queueMaxSize);
private ExecutorService executor = new MyThreadPoolExecutor(10, workQueue);
/**
* constructor
*/
private MyManager() {}
public static MyManager getInstance(){
if (manager == null){
synchronized(MyManager.class){
if (manager == null){
manager = new MyManager();
}
}
}
return manager;
}
/**
*/
public void executeTask(Integer key){
executeTask(key, Locale.getDefault());
}
/**
*/
public void executeTask(Integer key, Locale locale) {
Tasker task = new Tasker(key, locale);
executor.execute(task);
}
}
这里是要求完成任务的班级:
public class MyClass {
public void doTasks() {
//geting my tasks in array of list, its holding more than 900 000 tasks,
//sometimes its holding up to 10 million task like :
MyManager.getInstance().isFull() {\\wait, then ask again}
ArrayList<Integer> myTasks = getAllTasksIds();
for(Integer id : myTasks) {
//if i perform a waiting here it will be waiting for ever.
MyManaget.getInstance().executeTask(id);
}
}
}
我想要等待执行者直到完成队列任务,然后再重新填满它。
但问题是当我尝试根据队列大小等待时,执行器将无法工作,并且它会永远等待,因为队列仍然已满。
答案 0 :(得分:1)
为什么不使用有界阻塞队列(即指定BlockingQueue的边界)?如果使用有界阻塞队列(您可以自行选择其大小),则生产者将在队列已满时阻止,并在从队列中使用任务时继续发布任务。这样,您可以避免过多地将太多东西放到队列中,但也避免在队列上放置太少的东西。这就是阻止队列的重点......
答案 1 :(得分:0)
我测试了你的代码,但是我没有使用ArrayBlockingQueue,而是使用它进行扩展...而且它有效。试试吧:
public static class MyBlockingQueue extends ArrayBlockingQueue<Runnable> {
private static final long serialVersionUID= -9016421283603545618L;
public static Lock lock= new ReentrantLock();
public static Condition condition= lock.newCondition();
public static volatile Boolean isWaiting= false;
public MyBlockingQueue(int capacity) {
super(capacity, true);
}
@Override
public boolean offer(Runnable e) {
if (remainingCapacity() == 0) {
try {
isWaiting= true;
condition.await();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
return super.offer(e);
}
@Override
public Runnable take() throws InterruptedException {
Runnable take= super.take();
if (remainingCapacity() > 0 && isWaiting) {
isWaiting= false;
condition.signal();
}
return take;
}
}