我认为使用ThreadPoolExecutor我们可以在构造函数中传递的Runnable
或使用BlockingQueue
方法执行execute
。
另外我的理解是,如果任务可用,它将被执行
我不明白的是:
public class MyThreadPoolExecutor {
private static ThreadPoolExecutor executor;
public MyThreadPoolExecutor(int min, int max, int idleTime, BlockingQueue<Runnable> queue){
executor = new ThreadPoolExecutor(min, max, 10, TimeUnit.MINUTES, queue);
//executor.prestartAllCoreThreads();
}
public static void main(String[] main){
BlockingQueue<Runnable> q = new LinkedBlockingQueue<Runnable>();
final String[] names = {"A","B","C","D","E","F"};
for(int i = 0; i < names.length; i++){
final int j = i;
q.add(new Runnable() {
@Override
public void run() {
System.out.println("Hi "+ names[j]);
}
});
}
new MyThreadPoolExecutor(10, 20, 1, q);
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/*executor.execute(new Runnable() {
@Override
public void run() {
System.out.println("++++++++++++++");
}
}); */
for(int i = 0; i < 100; i++){
final int j = i;
q.add(new Runnable() {
@Override
public void run() {
System.out.println("Hi "+ j);
}
});
}
}
}
除非我在构造函数中取消注释executor.prestartAllCoreThreads();
或者调用打印execute
的runnable的System.out.println("++++++++++++++");
(它也被注释掉),否则此代码不会执行任何操作。
为什么?
引用(我的重点):
默认情况下,最初创建核心线程,仅启动 新任务到达时,但可以使用动态覆盖 方法prestartCoreThread()或prestartAllCoreThreads()。你可能 如果您使用非空构造池,则希望预启动线程 队列。
确定。所以我的队列不是空的。但我创建executor
,我做sleep
然后我将新的Runnable
添加到队列中(在循环中为100)。
此循环不计为new tasks arrive
吗?
为什么它不起作用,我必须prestart
或明确地致电execute
?
答案 0 :(得分:9)
当执行任务到达时,会生成工作线程,这些是与底层工作队列交互的线程。如果以非空工作队列开始,则需要预启动工作程序。请参阅implementation in OpenJDK 7。
我再说一遍,工作人员是与工作队列交互的人员。它们仅在通过execute
传递时按需生成。 (或者它上面的层,例如invokeAll
,submit
等。)如果它们没有启动,那么你添加到队列中的工作量无关紧要,因为没有任何东西将它检查为< strong>没有工人开始。
ThreadPoolExecutor
在必要之前或者通过方法prestartAllCoreThreads和prestartCoreThread抢先创建工作线程时不会生成工作线程。如果没有工作人员启动,则队列中的任何工作都无法完成。
添加初始execute
的原因在于它强制创建唯一核心工作线程,然后该线程可以开始处理队列中的工作。您也可以致电prestartCoreThread
并获得类似的行为。如果您想启动所有工作人员,您必须致电prestartAllCoreThreads
或通过execute
提交相应数量的任务。
请参阅下面execute
的代码。
/**
* Executes the given task sometime in the future. The task
* may execute in a new thread or in an existing pooled thread.
*
* If the task cannot be submitted for execution, either because this
* executor has been shutdown or because its capacity has been reached,
* the task is handled by the current {@code RejectedExecutionHandler}.
*
* @param command the task to execute
* @throws RejectedExecutionException at discretion of
* {@code RejectedExecutionHandler}, if the task
* cannot be accepted for execution
* @throws NullPointerException if {@code command} is null
*/
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* 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);
}
答案 1 :(得分:5)
BlockingQueue不是魔术线程调度程序。如果您将Runnable对象提交到队列并且没有正在运行的线程来使用这些任务,那么它们当然不会被执行。另一方面,如果需要,execute方法将根据线程池配置自动分派线程。如果你预先启动所有核心线程,那么就会有线程从队列中消耗任务。