Почему Java Thread спроектирован таким образом, что его нельзя перезапустить? [Дубликат]

Лакшман Прасад был прав, pip --upgrade и / или virtualenv --no-site-packages - это путь. Удаление общесистемных модулей python является плохим.

Параметр - upgrade для pip устанавливает установленные модули в виртуальном env, даже если они уже существуют в системной среде, и даже если требуемая версия или последняя доступная версия совпадает с версией системы.

  pip --upgrade install  

И использование опции -no-site-packages при создании виртуальной среды гарантирует, что отсутствующие зависимости не могут возможно, замаскированы наличием недостающих модулей в системном пути. Это помогает выявлять проблемы при миграции модуля из одного пакета в другой, например. pinax.apps.groups -> django-groups, особенно когда проблема связана с инструкциями load templatetags в django, которые ищут все доступные модули для каталогов templatetags и определения тегов внутри.

14
задан Mike Nakis 4 March 2014 в 16:11
поделиться

9 ответов

Я знаю, что перезапустить использованный объект Java Thread невозможно, но я не нашел объяснения, почему это не разрешено; даже если гарантировано, что поток завершен (см. примерный код ниже).

Мое гадание состоит в том, что потоки могут быть напрямую привязаны (для эффективности или других ограничений) к фактическому native , которые могут быть перезапущены в некоторых операционных системах, но не в других. Если разработчики языка Java разрешили перезапускать Threads, они могут ограничить количество операционных систем, на которых может работать JVM.

Подумайте об этом, я не могу думать о ОС который позволяет перезапустить поток или процесс после его завершения или завершения. Когда процесс завершается, он умирает. Вы хотите другой, вы перезапустите его. Вы никогда не воскрешаете его.

. Помимо вопросов эффективности и ограничений, налагаемых базовой ОС, есть проблема анализа и рассуждений. Вы можете рассуждать о параллелизме, когда вещи либо неизменяемы, либо имеют дискретный, конечный срок службы. Как и государственные машины, они должны иметь состояние терминала. Это началось, дожидаясь, закончилось? Такие вещи не могут быть легко обоснованы, если вы разрешаете Threads воскресать.

Вы также должны учитывать последствия воскрешения потока. Восстановить свой стек, его состояние, безопасно воскресить? Можете ли вы воскресить нить, которая закончилась ненормально? И т. Д.

Слишком волосатый, слишком сложный. Все это для незначительных выгод. Лучше сохранить Threads как нересупретируемые ресурсы.

18
ответ дан luis.espinal 16 August 2018 в 06:50
поделиться

Темы Java следуют жизненному циклу, основанному на приведенной ниже диаграмме состояний. Когда поток находится в конечном состоянии, он закончен. Это просто дизайн. alt text [/g0]

1
ответ дан akf 16 August 2018 в 06:50
поделиться
  • 1
    Это понятно, но каковы причины, по которым он был спроектирован именно так? – Curd 27 October 2010 в 15:25
  • 2
    @Curd - см. Мой ответ. – luis.espinal 27 October 2010 в 15:29
  • 3
    Хорошая диаграмма :-). Тем не менее, это правда, что это не отвечает на вопрос ... – sleske 27 October 2010 в 16:32

Я поставил бы вопрос наоборот: почему должен перезапустить объект Thread?

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

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

(Это в целом похоже на аргумент о изменяемых переменных vs final - я нахожу конечные «переменные» гораздо проще рассуждать и скорее создали бы несколько новых постоянных переменных, чем повторное использование существующих.)

15
ответ дан Andrzej Doyle 16 August 2018 в 06:50
поделиться
  • 1
    Одной из причин желания restart является стоимость создания новых (и сбор мусора старых) объектов Thread. – Curd 27 October 2010 в 15:36
  • 2
    Затем просто используйте пул потоков, где каждый поток может быть повторно использован для нескольких Runnables. – Steve Kuo 27 October 2010 в 16:03
  • 3
    как говорит Стив, используйте механизм пула потоков. Мне нравится простота использования реализаций ExecutorService, которые могут быть получены с помощью статических методов класса Executors. Используйте runnables в качестве перезапускаемых задач. – Tom Neyland 27 October 2010 в 16:53
  • 4
    @Curd - вы профилировали свое приложение и обнаружили, что стоимость размещения объекта и потока GC составляет незначительную стоимость исполнения? Если вы не делаете что-то безумное , это почти наверняка не будет. И в этом случае просто отправьте Runnable s в пул потоков (например, ThreadPoolExecutor). – Andrzej Doyle 27 October 2010 в 17:51

Если вы обеспокоены накладными расходами на создание нового объекта Thread, вы можете использовать исполнители.

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class Testes {
    public static void main(String[] args) {
        Executor executor = Executors.newSingleThreadExecutor();
        executor.execute(new Testes.A());
        executor.execute(new Testes.A());
        executor.execute(new Testes.A());
    }   
    public static class A implements Runnable{      
        public void run(){          
            System.out.println(Thread.currentThread().getId());
        }
    }
}

Запустив это, вы увидите, что тот же поток используется для всех объектов Runnable.

0
ответ дан gfelisberto 16 August 2018 в 06:50
поделиться

A Thread не является нитью . Нить - это исполнение вашего кода. Thread - это объект, который ваша программа использует для создания и управления жизненным циклом потока .

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

Нить - это исполнение вашего кода. Не имеет смысла даже говорить о «повторном использовании» потока исполнения по той же причине, что бессмысленно говорить о повторном воспроизведении того же набора в теннисе. Даже если другое выполнение вашего кода выполняет все те же операторы в том же порядке, это все еще исполнение .

Анджей Дойл спросил: «Почему вы хотите для повторного использования Thread? " Почему? Если объект Thread представляет поток выполнения --- эфемерная вещь, о которой вы даже не можете говорить о повторном использовании, то зачем вам или ожидать объект Thread для повторного использования?

0
ответ дан james large 16 August 2018 в 06:50
поделиться

Вы можете обойти это, либо используя java.util.concurrent.ThreadPoolExecutor, либо вручную, имея поток, который вызывает Runnable.run() для каждого Runnable, который ему задан, а не фактически выходит, когда он закончен.

Это не совсем то, о чем вы спрашивали, но если вы беспокоитесь о времени строительства нити, это может помочь решить эту проблему. Вот пример кода для ручного метода:

public class ReusableThread extends Thread {
    private Queue<Runnable> runnables = new LinkedList<Runnable>();
    private boolean running;

    public void run() {
        running = true;
        while (running) {
            Runnable r;
            try {
                synchronized (runnables) {
                    while (runnables.isEmpty()) runnables.wait();
                    r = runnables.poll();
                }
            }
            catch (InterruptedException ie) {
                // Ignore it
            }

            if (r != null) {
                r.run();
            }
        }
    }

    public void stopProcessing() {
        running = false;
        synchronized (runnables) {
            runnables.notify();
        }
    }

    public void addTask(Runnable r) {
        synchronized (runnables) {
            runnables.add(r);
            runnables.notify();
        }
    }
}

Очевидно, это просто пример. Он должен иметь лучший код обработки ошибок и, возможно, больше настроек.

0
ответ дан Jonathan 16 August 2018 в 06:50
поделиться

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

С другой стороны, Runnable представляет задачу и может быть передана многим Потоки столько раз, сколько хотите.

2
ответ дан Mark Peters 16 August 2018 в 06:50
поделиться

Почему вы не хотите создавать новую тему? Если вы обеспокоены накладными расходами на создание своего объекта MyThread, сделайте его Runnable и запустите его с помощью new Thread(myThread).start();

1
ответ дан Paul Tomblin 16 August 2018 в 06:50
поделиться
  • 1
    Это все еще накладывает на одни и те же потоки создания потока , как только метод runnable run () заканчивается (или заканчивается внезапно). Способ избежать таких накладных расходов заключается в создании пулов потоков или пользовательских классов потоков, которые ждут пока они не получат messaged с Runnable (или некоторым другим командным объектом) для запуска. Как только он заканчивается, закрывающая нить переходит в режим сна, пока не получит / не получит другую. Или пул потребительских пользовательских потоков, потребляющих Runnable объекты, помещенные в очередь. – luis.espinal 27 October 2010 в 15:21
  • 2
    Это по-прежнему требует создания новых (и мусорных коллекций старых) объектов Thread. – Curd 27 October 2010 в 15:39
  • 3
    @ luis.espinal: Хорошая точка. Почему бы вам не написать это как ответ? – sleske 27 October 2010 в 16:33
  • 4
    @Curd: Нет, не так, как описывает luis.espinal. Фактический поток (т. Е. Экземпляр java.lang.Thread) никогда не заканчивается, он просто ждет, когда это будет сделано, пока не получит новый Runnable. Создаются только Runnable и GCed, и они могут быть такими же легкими, как вам нужно. – sleske 27 October 2010 в 16:35
  • 5
    Накладные расходы на создание потоков неизбежны. – Paul Tomblin 27 October 2010 в 17:28

Я искал то же самое решение, которое вы, похоже, ищете, и я решил его таким образом. если вы обнаружите событие mousePressed, вы можете его закончить и повторно использовать, но его нужно инициализировать, как показано ниже.

class MouseHandler extends MouseAdapter{
    public void mousePressed(MouseEvent e) {            
        if(th.isAlive()){
            th.interrupt();
            th = new Thread();
        }
        else{
            th.start();
        }
    }

}
-1
ответ дан user3671438 16 August 2018 в 06:50
поделиться
  • 1
    Это фактически создает новый поток, не перезагружая старый объект потока. – Sebastian Lange 24 May 2014 в 11:31
Другие вопросы по тегам:

Похожие вопросы: