2014-12-16 4 views
0

У меня есть исполнитель с конечными границами, и он использует CallerRunsPolicy. Поэтому, когда я отправляю слишком много заданий, я сталкиваюсь с RejectedExecutionException, и моя работа выполняется в вызывающем потоке.Определите, когда выполняется CallerRunsPolicy.

Предполагается, что задание просто печатает, выполняется ли оно в службе исполнителя или в вызывающем потоке. Каков наилучший способ достижения этого? Есть ли встроенная видимость, когда задание выполняется в потоке вызывающего?

Одним из возможных решений, о которых я думаю, является расширение Runnable и CallerRunsPolicy, а затем переопределение rejectedExecution(Runnable r, ThreadPoolExecutor executor) для хранения флага в Runnable.

class CustomRunnable implements Runnable 
{ 
    @Override 
    public void run() 
    { 
     if(willExecuteOnCallingThread) // Running on new thread. 
     else // Running on calling thread. 
    } 
    boolean willExecuteOnCallingThread = false; 
} 

class LoggedCallerRunsPolicy extends CallerRunsPolicy 
{ 
    @Override 
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) 
    { 
     ((CustomRunnable)r).setWillExecuteOnCallingThread(true); 
     super.rejectedExecution(r, executor); 
    } 
} 

ответ

0

Немного сложное, но надежное решение. Добавьте дополнительную очередь (так называемый Q1) и поток (называемый Thr1) между вашим вызывающим потоком & исполнителями. Вызов потока просто добавляется в Q1, Thr1 потребляет до Q1 и дает задание службе-исполнителям. executorservice делает дополнительную операцию после завершения собственной работы, которая уведомляет об этом поток Thr1. Thr1 уведомит и извлечет из Q1 задачу ExecutorService.

0

API не предоставляет встроенный метод для получения этой информации, просто потому, что вы не должны писать задачи, которые каким-либо образом зависят от исполняемого потока.

Если вы все еще настаиваете на записи этой информации, использование специализированного RejectedExecutionHandler является правильным способом, однако вы не должны устанавливать флаг на Runnable. В принципе, Runnable может быть поставлен в очередь несколько раз и даже выполнен несколькими потоками одновременно. Возможно, даже в том случае, если он выполняется одним объединенным потоком и одним потоком вызывающего абонента одновременно.

В конце концов, вам не нужен изменяемое состояние, ни условные для его реализации:

class CustomRunnable implements Runnable { 
    @Override 
    public void run() { 
     System.out.println("executed by pool thread"); 
     actualAction(); 
    } 
    public void callerRun() { 
     System.out.println("executed by submitting (aka caller) thread"); 
     actualAction(); 
    } 
    private void actualAction() { 
     // … perform your action independently of the executing thread 
    } 
} 

class LoggedCallerRunsPolicy implements RejectedExecutionHandler { 
    @Override 
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { 
     if(r instanceof CustomRunnable) 
      ((CustomRunnable)r).callerRun(); 
     else 
      r.run(); 
    } 
} 

Но имейте в виде, что это работает только если CustomRunnable был поставлен в очередь с помощью execute. Если runnable был поставлен в очередь на submit, он будет завернут в RunnableFuture, и эта оболочка будет передан либо в очередь, либо в очередь, либо в RejectedExecutionHandler.