Я читаю исходный код ThreadPoolExecutor.java
для метода execute
, описанного ниже:
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);
}
Предположим, что в пуле потоков есть 2 основных потока, а максимальный размер пула равен 4.
Я могу понять код if (workerCountOf(c) < corePoolSize) { addWorkder(..) }
, это означает, что если в настоящее время число основных потоков меньше, чем размер опроса ядра, просто создайте новый поток для обработки команды runnable.
Что я не могу понять, так этоСкажем, если мы уже два раза звонили execute(runnable)
, и каждому из них требуется много времени для завершения, поэтому они все еще заняты, и теперь мы звоним в третий раз.
Что будет делать код?Я думаю, что код идет к if (isRunning(c) && workQueue.offer(command)) {
, поэтому команда добавляется в рабочую очередь.Однако я не понимаю, какая третья команда будет выполняться каким потоком.Согласно коду else if (workerCountOf(recheck) == 0)
, я думаю, что количество рабочих должно быть 2, потому что мы уже добавили двух рабочих.
Поэтому мой вопрос, когда будет добавлен 3-й рабочий?
- Правка-
Мой код тестирования:
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2,
4,
60,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(4)
);
threadPoolExecutor.execute(new Command("A"));
threadPoolExecutor.execute(new Command("B"));
threadPoolExecutor.execute(new Command("C"));
}
static class Command implements Runnable {
private String task;
Command(String task) {
this.task = task;
}
@Override
public void run() {
try {
Thread.sleep(1000 * 10);
System.out.println(new Date() + " - " + Thread.currentThread().getName() + " : " + task);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Он печатает:
Thu Jun 13 17:44:30 CST 2019 - pool-1-thread-1 : A
Thu Jun 13 17:44:30 CST 2019 - pool-1-thread-2 : B
Thu Jun 13 17:44:40 CST 2019 - pool-1-thread-1 : C
С кодом тестирования я ожидаю, что основные работники будут заняты в течение 10 секунд, поэтомукогда execute("C")
я хочу обратить внимание на случай «основные работники заняты, и третий работник будет добавлен», но кажется, что третьего работника нет?Извините, но что не так?
Спасибо.