повторное использование потока Java через исполнителя - PullRequest
5 голосов
/ 19 сентября 2010

Я запутался в следующем:
Чтобы использовать потоки в Java-программе, самый простой способ - расширить класс Thread и реализовать исполняемый интерфейс (или просто реализовать работающий).
Чтобы начать выполнение потока. мы должны вызвать метод потока start (), который в свою очередь вызывает метод run () потока. И так начинается поток.
Метод start () (если я не ошибаюсь) должен вызываться точно и только один раз для каждого потока. В результате экземпляры потока не могут быть повторно использованы, если сам метод run не выполняется в некотором смысле бесконечного цикла, что облегчает пользовательскую реализацию повторного использования потока.
Теперь Javadoc текст ссылки говорит

Вызовы для выполнения будут повторно использовать ранее созданные потоки, если они доступны

Я не понимаю, как это реализовано. Я предоставляю в методе execute метода executor мой пользовательский поток, например

  ExecutorService myCachedPool = Executors.newCachedThreadPool();
  myCachedPool.execute(new Runnable(){public void run(){  
     //do something time consuming

  }});

Как можно повторно использовать этот пользовательский поток, который я удаляю в среду executor?
Разрешено ли Executor вызывать метод start () более 1 раза, а мы не можем в наших программах? Я что-то неправильно понимаю?

Спасибо.

Ответы [ 3 ]

5 голосов
/ 19 сентября 2010

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

Каждый поток в пуле потоков может просто wait() для Исполнителя передать ему новый Runnable, но собственный метод потока run()не завершено.Он просто ждет, когда новый Runnable будет передан Исполнителю.

4 голосов
/ 19 сентября 2010

Обратите внимание, что не Executor вызывает start() - это ExecutorService. И нет, он не звонит start() дважды. Он не запускает задачу, которую вы передаете ему напрямую, используя Thread.start() ... вместо этого он запускает поток, который знает об очереди работы этого пула потоков. Поток, в основном, будет ждать выполнения некоторой работы, затем подхватит ее и выполнит, прежде чем вернуться к ожиданию. Таким образом, хотя поток выполняет несколько задач, Thread.start() вызывается только один раз.

РЕДАКТИРОВАТЬ: Судя по комментариям, вы немного озадачены разницей между Runnable (это задача, которая должна быть выполнена) и Thread (это то, что выполняет задачи).

Один и тот же поток может выполнять несколько задач. Для очень простого примера, не использующего пул потоков, рассмотрим это:

public class MultiRunnable implements Runnable
{
    private final List<Runnable> runnables;

    public MultiRunnable(List<Runnable> runnables)
    {
        this.runnables = runnables;
    }

    public void run()
    {
        for (Runnable runnable : runnables)
        {
             runnable.run();
        }
    }
}

(Игнорировать потенциальные проблемы безопасности потоков при использовании List<T> из нескольких потоков.)

Вы можете создать целую группу Runnable задач, способных выполнять разные задачи, а затем создать одну MultiRunnable, чтобы запускать их по очереди. Передайте этот экземпляр MultiRunnable в конструктор Thread, а затем при запуске потока он выполнит каждую из исходных выполняемых задач. Это помогает?

1 голос
/ 19 сентября 2010

Чтобы «запустить» поток более одного раза, создайте работоспособный объект. Например:

//NO
private class T extends Thread { //not necessary to implement runnable
    public void run(){
        //...
    }
}
void someMethod(){
    T a = new T();
    a.start();
    a.start(); //NO NO NO NO NO NO NO NO NO NO NO NO NO NO NO NO NO
}

Вместо

//Yes
private class T implements Runnable {
    public void run(){
        //...
    }
}
void someMethod(){
    T a = new T();
    new Thread(a).start();
    new Thread(a).start(); //YES YES YES
}

Также возможно сделать это:

void someMethod(){
    final Runnable r = new Runnable(){
        public void run(){
            //...
        }
    };
    new Thread(r).start();
    new Thread(r).start();
}
// r could also be a field of you class. 
...