Добавление потока в ThreadPool в службе исполнителя

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

Ниже мой код-

class ThreadTask implements Runnable {
    private final long endTime;

    public ThreadTask(long endTime) {
        this.endTime = endTime;
    }

    @Override
    public void run() {

        while (System.currentTimeMillis() <= endTime) {

            // do something meaningful

        }   
    }
}

public class TestPool {

    public static void main(String[] args) {

        // create thread pool with given size
        ExecutorService service = Executors.newFixedThreadPool(1000); 

        long startTime = System.currentTimeMillis();
        long endTime = startTime + (30 * 60 * 1000);

        for (int i = 0; i < threads; i++) {
            service.submit(new ThreadTask(endTime));
        }

        // wait for termination        
        service.shutdown();
        service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); 
    }
}

Теперь мой вопрос:

Гарантирует ли приведенный выше код, что каждый поток запускается в одно и то же время и работает в течение 30 minutes? Я не уверен, сколько времени требуется для помещения потока в пул потоков. Но похоже, что некоторые потоки могут начаться с небольшим опозданием, и они не будут работать ровно 30 minutes, может быть меньше 30 минут.

Я ищу, чтобы каждый поток начинался в одно и то же время, и они должны работать ровно 30 minutes


person AKIWEB    schedule 05.03.2013    source источник
comment
Нет, они не запустятся одновременно и не будут работать ровно 30 минут в зависимости от того, сколько времени займет что-то значимое.   -  person Brian Roach    schedule 05.03.2013


Ответы (3)


Короткий ответ: нет, все потоки не будут запускаться точно в одно и то же время (в зависимости от ваших допусков это может быть «совершенно» незначительным). И в зависимости от того, что делает что-то значимое, очень мало шансов, что каждый поток будет работать ровно 30 минут (опять же здесь, ваша временная гранулярность может сделать это утверждение неверным).

Лиды:

  • Чтобы максимизировать ваши шансы на то, что все потоки начнутся как можно ближе друг к другу, сначала создайте свои потоки, а затем отправьте их исполнителю. Создание потока в Java, как и в других языках, является дорогостоящей операцией.
  • Чтобы потоки выполнялись ровно 30 минут, я бы рекомендовал, чтобы каждый поток сам вычислял время своего завершения, поскольку аргумент, который вы сейчас передаете конструктору, уже может повлиять на вашу точность (из-за времени создания потока).
  • Обычно не рекомендуется (за исключением случаев, когда вы запускаете java на машине-монстре или в вычислительной сетке) создавать пул потоков с 1000 потоков. Имейте в виду, что если на физической машине ядер меньше, чем потоков, переключение контекста будет происходить каждый раз, когда JVM решает, какой поток следует запустить.

ИЗМЕНИТЬ:

public class TestPool {

    public static void main(String[] args) {

        // create thread pool with given size
        ExecutorService service = Executors.newFixedThreadPool(10); 

        long startTime = System.currentTimeMillis();
        long endTime = startTime + (30 * 60 * 1000);

        ThreadTask[] threadTasks = new ThreadTask[threads];
        for (int i = 0; i < threads; i++) {
            threadTasks[i] = new ThreadTask(endTime);
        }

        for (ThreadTask tt : threadTasks) {
            service.submit(tt);
        }

        // wait for termination        
        service.shutdown();
        service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); 
    }
}
person aymeric    schedule 05.03.2013
comment
Спасибо aymeric за предложение. Меня больше всего интересует ваш первый пункт. Как я могу этого добиться? Можете ли вы привести пример с моим кодом? Благодаря этому я смогу лучше понять. Спасибо за помощь. - person AKIWEB; 06.03.2013

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

Если это так: не создавайте 1000 тем только потому, что можете. Вместо этого скажите, чего вы на самом деле хотите достичь.

О ваших требованиях: Чтобы запустить все потоки почти одновременно с минимальной задержкой, вы можете prestartAllCoreThreads из ThreadPoolExecutor. Отправьте Runnables, у которых есть // do something meaningful в их методе запуска. Чтобы ограничить время выполнения 30 минутами, запланируйте TimerTask, который через 30 минут выключит ThreadPoolExecutor с помощью shutdownNow. При создании ThreadPoolExecutor вы можете использовать BlockingQueue фиксированного размера с размером в порядке желаемого количества потоков, чтобы избежать отправки слишком большого количества заданий.

person Ralf H    schedule 05.03.2013

Рассмотрите возможность использования защелки обратного отсчета для достижения максимального параллелизма. По сути, вы можете создать singleton/static countdownLatch с общим количеством 1 и позволить нескольким потокам ожидать одного и того же обратного отсчета. проверьте ниже, что я сделал

Основной поток, определяющий время запуска потока.

package mylab.threads;

import java.util.TimerTask;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MainThread extends TimerTask {

    private static CountDownLatch countDown = new CountDownLatch(1);

    private ExecutorService es = Executors.newCachedThreadPool();

    @Override
    public void run() {

    try {


        Thread1 thread1 = new Thread1();
        thread1.setDoneSignal(countDown);
        es.submit(thread1);

        Thread2 thread2 = new Thread2();
        thread2.setDoneSignal(countDown);
        es.submit(thread2);

        System.out.println("waiting main.. ");
        synchronized(this) {
        this.wait(2000);
        }
        System.out.println("kick off threads..");
        countDown.countDown();

    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    }

}

Определите потоки, которые вы хотите запустить параллельно

package mylab.threads;

import java.util.Date;
import java.util.TimerTask;
import java.util.concurrent.CountDownLatch;

public class Thread1 extends TimerTask{

    private CountDownLatch doneSignal = null;

    /**
     * @return the doneSignal
     */
    public CountDownLatch getDoneSignal() {
        return doneSignal;
    }

    /**
     * @param doneSignal the doneSignal to set
     */
    public void setDoneSignal(CountDownLatch doneSignal) {
        this.doneSignal = doneSignal;
    }

    @Override
    public void run() {

    try {
        this.doneSignal.await();
        System.out.println("get going thread 1 -"+new Date().getTime());
        synchronized(this) {
        this.wait(3000);
        }
        System.out.println("Exiting thread 1 - "+new Date().getTime());
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    }

}


package mylab.threads;

import java.util.Date;
import java.util.TimerTask;
import java.util.concurrent.CountDownLatch;

public class Thread2 extends TimerTask{

    private CountDownLatch doneSignal = null;

    /**
     * @return the doneSignal
     */
    public CountDownLatch getDoneSignal() {
        return doneSignal;
    }

    /**
     * @param doneSignal the doneSignal to set
     */
    public void setDoneSignal(CountDownLatch doneSignal) {
        this.doneSignal = doneSignal;
    }

    @Override
    public void run() {

    try {
        this.doneSignal.await();
        System.out.println("get going thread 2 -"+new Date().getTime());
        synchronized(this) {
        this.wait(3000);
        }
        System.out.println("Exiting thread 2 - "+new Date().getTime());
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    }
}

Наконец, запустите основной поток.

package mylab.threads;

public class ThreadTest {

    /**
     * @param args
     */
    public static void main(String[] args) {

    MainThread mt = new MainThread();
    mt.run();

    }

}

Вот результат

waiting main.. 
kick off threads..
get going thread 1 -1387513662107
get going thread 2 -1387513662107
Exiting thread 1 - 1387513665108
Exiting thread 2 - 1387513665108
person Charith De Silva    schedule 20.12.2013