Подтвердить что ты не робот

ExectuorService vs ThreadPoolExecutor (который использует LinkedBlockingQueue)

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

Ниже приведен код, который использует ExecutorService -

public class MultithreadingExample {

    public static void main(String[] args) throws InterruptedException {

        ExecutorService executor = Executors.newFixedThreadPool(20);
        for (int i = 0; i < 100; i++) {
            executor.submit(new NewTask());
        }

        executor.shutdown();
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
    }
}

class NewTask implements Runnable {

    @Override
    public void run() {
        //Measure the end to end latency of my client code
    }   
}

Проблема: -

Теперь я читал статью в Интернете. Я узнал, что есть -

ThreadPoolExecutor. Поэтому я смутился, какой из них я должен использовать.

Если я заменил свой код выше -

ExecutorService executor = Executors.newFixedThreadPool(20);
    for (int i = 0; i < 100; i++) {
        executor.submit(new NewTask());
    }

к -

BlockingQueue<Runnable> threadPool = new LinkedBlockingQueue<Runnable>();

ThreadPoolExecutor tpExecutor = new ThreadPoolExecutor(20, 2000, 0L, TimeUnit.MILLISECONDS, threadPool);

tpExecutor.prestartAllCoreThreads();

    for (int i = 0; i < 100; i++) {
        tpExecutor.execute(new NewTask());
    }

тогда это будет иметь какое-то значение? Я пытаюсь понять, в чем разница между моим исходным кодом, который использует ExecutorService, и новым кодом, который я вставил, который использует ThreadPoolExectuor? Некоторые из моих товарищей по команде сказали, что второй (ThreadPoolExecutor) правильный способ использования?

Может ли кто-нибудь прояснить эту вещь для меня? Спасибо за помощь.

4b9b3361

Ответ 1

Вот источник Executors.newFixedThreadPool:

 public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

Он внутренне использует класс ThreadPoolExecutor с конфигурацией по умолчанию, как вы можете видеть выше. Теперь есть сценарии, в которых конфигурация по умолчанию не подходит, вместо LinkedBlockingQueue необходимо использовать приоритетную очередь и т.д. В таких случаях вызывающий может непосредственно работать с базовым ThreadPoolExecutor, создавая его и передавая ему нужную конфигурацию.

Ответ 2

то это будет иметь значение?

Это сделает ваш код более сложным для небольшой выгоды.

Я пытаюсь понять, в чем разница между моим исходным кодом, использующим ExecutorService, и новым кодом, который я вставил, который использует ThreadPoolExectuor?

Рядом ни с чем. Executors создает ThreadPoolExecutor для выполнения реальной работы.

Некоторые из моих товарищей по команде сказали, что второй (ThreadPoolExecutor) является правильным способом использования?

Просто потому, что это сложнее, это не значит, что это правильно. Дизайнеры предоставили методы Executors.newXxxx, чтобы сделать жизнь проще для вас и потому, что они ожидали, что вы будете использовать эти методы. Я также предлагаю вам использовать их.

Ответ 3

в основном

 return new ThreadPoolExecutor(20, 20,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());

2.

BlockingQueue<Runnable> threadPool = new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor tpExecutor = new ThreadPoolExecutor(20, 2000, 0L,
    TimeUnit.MILLISECONDS, threadPool);

Во втором случае вы просто увеличиваете maxPoolSize до 2000, что, я сомневаюсь, вам понадобится.

Ответ 4

Я считаю, что еще одно преимущество заключается в RejectionHandler. Исправьте меня, если неправильно

Ответ 5

Через 2 дня GC out of memory exception, ThreadPoolExecutor спас мою жизнь.:)

Как сказал Баладжи,

[..] еще одно преимущество - RejectionHandler.

В моем случае у меня было много RejectedExecutionException и указание (как следует) политика сброса разрешила все мои проблемы.

private ThreadPoolExecutor executor = new ThreadPoolExecutor(1, cpus, 1, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.DiscardPolicy());

Но будьте осторожны! Он работает, только если вы не должны выполнять все потоки, которые вы отправляете исполнителю.

Для получения дополнительной информации о ThreadPoolExecutor см. ответ Даррена

Ответ 6

В первом примере вы создали только 20 потоков с инструкцией ниже

ExecutorService executor = Executors.newFixedThreadPool(20);

Во втором примере вы установили диапазон ограничений потоков между 20 to 2000

 ThreadPoolExecutor tpExecutor = new ThreadPoolExecutor(20, 2000, 0L, 
                                     TimeUnit.MILLISECONDS,threadPool);

Дополнительные потоки доступны для обработки. Но вы настроили очередь задач как неограниченную очередь.

ThreadPoolExecutor будет более эффективным, если вы настроили многие или все нижеуказанные параметры.

ThreadPoolExecutor(int corePoolSize, 
               int maximumPoolSize, 
               long keepAliveTime, 
               TimeUnit unit, 
               BlockingQueue<Runnable> workQueue, 
               ThreadFactory threadFactory,
               RejectedExecutionHandler handler)

RejectedExecutionHandler было бы полезно, если вы установите max capacity for workQueue и количество задач, которые были отправлены в Executor, больше чем workQueue.

Обратите внимание на раздел "Отклоненные задания" в ThreadPoolExecutor для более подробной информации.