Java — поток с использованием службы исполнителя

Я изучаю службу исполнителя в java. Требуется использовать службу исполнителя для создания 4 потоков -

Thread 1 - получить два числа на вход.

Тема 2 - сложение двух чисел

Тема 3 - умножение двух чисел

Тема 4 - распечатать результаты.

Поток 1 должен выполняться первым, после завершения потока 1 потоки 2, 3 могут начать обработку одновременно и, наконец, после завершения потоков 2, 3. Наконец должен запуститься поток 4.

Как мы можем убедиться, какой поток запускается первым и какие потоки должны запускаться одновременно следующими? Наконец, какой поток выполнить в конце.

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


person Community    schedule 02.02.2020    source источник
comment
Поток 1 может запустить поток 2 и 3 (и, возможно, поток 4). Поток 4 может присоединиться ко всем потокам.   -  person dan1st    schedule 02.02.2020
comment
Что вы пробовали и что не работает с ним?   -  person daniu    schedule 02.02.2020
comment
К вашему сведению, это упражнение может научить вас чему-то как использовать потоки, но это абсолютно худший пример того, зачем использовать потоки. Это похоже на то, что кто-то учит вас управлять автомобилем, заставляя вас использовать передний бампер автомобиля, чтобы забивать гвозди в предмет мебели, который вы собираете. Я серьезно. Этот пример настолько плох. Если программе необходимо выполнить определенные действия в определенном порядке, единственный правильный способ сделать это — выполнить все эти действия в одном потоке. Весь смысл потоков в том, чтобы дать вам возможность делать что-то одновременно (то есть в произвольном порядке).   -  person Solomon Slow    schedule 02.02.2020
comment
Также обратите внимание: не думайте о службе исполнителя как о способе создания потоков. Думайте об этом как о способе выполнения фоновых задач. Весь смысл службы-исполнителя состоит в том, чтобы максимально оградить вас от необходимости думать о рабочих потоках, которые она использует для выполнения ваших задач. .   -  person Solomon Slow    schedule 03.02.2020


Ответы (2)


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

Например, присоединение:

Поток может присоединиться к другому потоку, что означает, что он ожидает завершения другого потока. Потоки 2 и 3 могут присоединиться к потоку 1, а поток 4 может присоединиться к потокам 2 и 3.

Другой вариант — ожидание и сигнал, но я не уверен, соответствует ли он вашим требованиям (он использует что-то похожее на Thread.sleep():

Сначала вы создаете общий java.util.concurrent.locks.Lock и создаете условие этой блокировки с помощью .newCondition(). Вы также создаете второе условие с помощью newCondition().

Блокировка должна быть заблокирована перед вызовом await и signal/signalAll.

Потоки 2 и 3 вызывают .await() для первого условия перед запуском, а поток 1 вызывает .signalAll для первого условия после завершения.

Поток 4 вызывает .await() по второму условию перед его запуском.

Поток (2 или 3), который завершается последним (логика того, какой поток завершился первым, должна быть синхронизирована с блокировкой), вызывает .signal() по второму условию.

Потоки также могут инициировать друг друга:

Поток 1 запускает потоки 2 и 3 после завершения своей задачи, но я бы рекомендовал вам один из других механизмов для потока 4.

[ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ]

Возможно, вы не сможете взаимодействовать с потоками напрямую, если используете файл ExecutorService. Этот пост может помочь вам присоединиться, await/signal не должно быть сложнее, а потоки также могут планировать задачу на пул потоков, если это необходимо.

person dan1st    schedule 02.02.2020
comment
Большое спасибо. Я понял вашу идею в базовой концепции потока Java. Действительно ли эта концепция такая же и в Java 8? - person ; 02.02.2020

Во-первых, прочтите мой комментарий к вашему исходному вопросу — об использовании автомобиля для забивания гвоздей.

Хорошо, теперь у @dan1st есть несколько идей о том, как структурировать решение. Вот еще два.

  1. Используйте глобальную переменную int, глобальную переменную lock, а также wait() и notifyAll(): Пусть каждый поток вводит блок synchronized(lock), в котором он

    • Loops, calling lock.wait() until the global int has some particular value,
    • Делает свой трюк,
    • Устанавливает глобальный int на значение, которое вызовет следующий поток,
    • вызывает lock.notify() и, наконец,
    • выходит
  2. Используйте Semaphores: передайте два экземпляра Semaphore в каждый поток. Назовите их in и out или что-то в этом роде. Иметь каждый поток

    • wait its turn by calling in.acquire(),
    • сделать свое дело,
    • звоните out.release(),
    • а затем выйти.

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


ИМО, вариант 2 более элегантен, потому что, если ваш учитель попросит вас на следующей неделе изменить вашу программу, добавив еще один шаг в середине последовательности, тогда ни одна из существующих задач, которые вы написали, не должна будет меняться вообще. Вам нужно будет только написать новую задачу и изменить две или три строки в процедуре main().

Не похоже на значительное улучшение, и вариант 2 явно требует больше усилий для настройки, чем вариант 1, но если вы когда-либо работали над программными системами корпоративного масштаба с миллионами строк кода, вы придет оценить красоту варианта 2.

person Solomon Slow    schedule 02.02.2020
comment
P.S. Если я когда-нибудь буду вести урок программирования, мои ученики будут учиться очень быстро, чтобы ожидать, теперь измените программу, которую вы написали на прошлой неделе, чтобы... В реальном мире требования меняются. Часто. Один из самых важных навыков, которым может овладеть разработчик, — это умение писать код, который не придется выбрасывать и начинать с нуля каждый раз, когда меняются требования. - person Solomon Slow; 02.02.2020