Я не могу получить RejectedExecutionException с ExecutorService - PullRequest
0 голосов
/ 22 октября 2018

Создаю планировщик для тестовой обработки RejectedExecutionException:

@Component
public class TestScheduler {

    private final TestService testService;
    private ExecutorService executorService;

    public TestScheduler(TestService testService) {
        this.testService = testService;
    }

    @PostConstruct
    public void init() {
        executorService = Executors.newFixedThreadPool(5);
    }

    @Scheduled(fixedRate = 10L)
    public void test() {
        System.out.println("test");
        executorService.execute(testService::print);
    }
}

и службы с задержкой 70 секунд:

@Component
public class TestService {

    public void print() {
        System.out.println("print start");
        try {
            TimeUnit.SECONDS.sleep(70);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("print end");
    }
}

Жду следующей логики:

  1. Вызов планировщика executorService.execute(testService::print) 5 раз
  2. Каждый testService::print будет выполняться 70 секунд
  3. Когда execute метод будет вызываться в шестой раз, я получу RejectedExecutionException

Но я не получаю исключения.У меня есть эти журналы:

test
print start
2018-10-22 11:26:45.543  INFO 5960 --- [           main] c.e.s.SchedullerExceptionsApplication    : Started SchedullerExceptionsApplication in 0.661 seconds (JVM running for 1.108)
test
print start
test
print start
test
print start
test
print start
test
...
70 seconds print test

РЕДАКТИРОВАТЬ

В реальном проекте у меня есть этот код:

@PostConstruct
    public void init() {
        executorService = Executors.newFixedThreadPool(100, new CustomizableThreadFactory("SendRequestExecutor-"));
    }

@Scheduled(fixedDelay = 1000L)
public void sendReady() {
    try {
        List<Message> messages = messageService.findReadyToSend();
        for (Message message : messages) {
            message.setStatus(IN_PROCESS);
            Message savedMessage = messageService.save(message);
            executorService.execute(() -> sendRequestService.send(savedMessage.getGuid()));
        }
    } catch (Exception e) {
        log.error("handle: " + e.getMessage());
    }
}

означает ли это, что этот коднеправильно?потому что это может произойти, поэтому я поменяю сущность на статус IN_PROCESS, а при попытке выполнить - если executorService full, я не получу исключение и executorService не выполнит мою задачу?

Ответы [ 2 ]

0 голосов
/ 22 октября 2018

При определении исполнителя есть два аспекта.

  1. Количество потоков, которые будут использоваться исполнителем. Это накладывает ограничение на количество одновременных задач.исполнитель может бежать.Это то, что вы устанавливаете с помощью Executors.newFixedThreadPool(5).
  2. Размер очереди отправки базовой задачи. Это накладывает ограничение на количество задач, которые базовая очередь может хранить до тех пор, пока она не сгенерируетисключение.Исполнитель, созданный newFixedThreadPool, использует неограниченную очередь, поэтому вы не получите исключение.

Вы можете достичь желаемого поведения, создав собственную службу исполнителя следующим образом и отправив ей 11 задач (5 для использования всех потоков, 5 для заполнения основной очереди задач и 1 для ее переполнения).

new ThreadPoolExecutor(5, 
                       5, 
                       2000L, 
                       TimeUnit.MILLISECONDS, 
                       new ArrayBlockingQueue<Runnable>(5, true), 
                       new ThreadPoolExecutor.CallerRunsPolicy());
0 голосов
/ 22 октября 2018

RejectedExecutionException будет вам брошено очередь задач переполнения (и это сейчас не связано), в то время как вы ожидаете, что она будет выброшена, когда вы запланируете больше задач (поместите ее, вероятно, в неограниченную очередь), чем выиметь рабочих - это бессмысленно, так как это своего рода цель рабочего - построить очередь и выполнить из нее.

Чтобы проверить обработку ошибок, либо издевайтесь над исполнителем и генерируйте исключение при отправке задачи (предпочтительно), либо используйте ограниченноеограниченная, неблокирующая очередь как резервная очередь для вашего исполнителя.

Использование mock - самый простой способ сделать это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...