Многопоточность в Java. Очередность выполнения потоков

Буду очень благодарен за подсказку, как правильно вывести на печать результаты решения задания с потоками на языке Java . При выводе на печать результаты по некоторым потокам "налезают" друг на друга. Нужно сделать так, чтобы потоки выполнялись и выводились на печать не пересекаясь, один после другого, в заданной очередности. Т.е. при выводе на печать в консоли должно быть следующее:

  1. Создать класс, реализующий интерфейс Runnable. Реализовано на примере создания счётчика от 1-го до 5-ти: Runnable count 1 Runnable count 2 Runnable count 3 Runnable count 4 Runnable count 5

  2. Переопределить run() метод. Создать цикл for. В цикле распечатать значения от 0 до 100 делящиеся на 10 без остатка: 0 10 20 30 40 50 60 70 80 90 100

  3. Использовать статический метод Thread.sleep(), чтобы сделать паузу. Реализовано путём создания паузы 1500 миллисекунд между выводом на печать значений счетчика '1' и '2': Counter value: 1 Counter value: 2

  4. Создать три потока, выполняющих задачу распечатки значений. Реализовано на примере вывода уведомлений о старте и финише трёх потоков: Thread1 started Thread2 started Thread3 started Thread1 finished Thread2 finished Thread3 finished

Спасибо. Вот мой код:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
    static final List<String> strings = Collections.synchronizedList(new ArrayList<>());

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

        ExecutorService service1 = Executors.newFixedThreadPool(1);
        Thread t1 = new Thread(new MyThread1());
        t1.start();
        service1.shutdown();

        ExecutorService service2 = Executors.newFixedThreadPool(1);
        Thread t2 = new Thread(new MyThread2());
        t2.start();
        service2.shutdown();

        ExecutorService service3 = Executors.newFixedThreadPool(1);
        Thread t3 = new Thread(new MyThread3());
        t3.start();
        service3.shutdown();

        ExecutorService service4 = Executors.newFixedThreadPool(1);
        Thread t4 = new Thread(new MyThread4());
        t4.start();
        service4.shutdown();

    }

    static class MyThread1 implements Runnable {
        @Override
        public void run() {
            synchronized (strings) {
                System.out.println("1. Создать класс, реализующий интерфейс Runnable." +
                        "\nРеализовано на примере создания счётчика от 1-го до 5-ти:");

                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(600);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Runnable count " + (i + 1));
                }
                System.out.println();
            }
        }
    }

    static class MyThread2 implements Runnable {
        @Override
        public void run() {
            synchronized (strings) {
                System.out.println("2. Переопределить run() метод. Создать цикл for. В цикле распечатать значения " +
                        "\nот 0 до 100 делящиеся на 10 без остатка:");

                for (int i = 0; i <= 100; i++) {
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (i % 10 == 0) {
                        System.out.println(i);
                    }
                }
                System.out.println();
            }
        }
    }


    static class MyThread3 implements Runnable {
        @Override
        public void run() {
            synchronized (strings) {
                System.out.println("3. Использовать статический метод Thread.sleep(), чтобы сделать паузу." +
                        "\nРеализовано путём создания паузы 1500 миллисекунд между выводом на печать " +
                        "\nзначений счетчика '1' и '2':");

                for (int i = 0; i < 2; i++) {
                    try {
                        Thread.sleep(1500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Counter value: " + (i + 1));
                }
                System.out.println();
            }
        }
    }


    static class MyThread4 implements Runnable {
        @Override
        public void run() {
            synchronized (strings) {

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("4. Создать три потока, выполняющих задачу распечатки значений." +
                        "\nРеализовано на примере вывода уведомлений о старте и финише трёх потоков:");
                try {
                    Thread.sleep(400);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                for (int i = 0; i < 3; i++) {
                    System.out.println("Thread" + (i + 1) + " started");
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                for (int i = 0; i < 3; i++) {
                    System.out.println("Thread" + (i + 1) + " finished");
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
            System.exit(0);
        }
    }
}

Ответы (1 шт):

Автор решения: DeMaz

При одновременном запуске нескольких потоков невозможно предсказать их очередность выполнения. Чтобы потоки выполнялись в заданном порядке можно использовать .join():

public static void main(String[] args) throws InterruptedException {
        
        Thread t1 = new Thread(new MyThread1());
        t1.start();
        t1.join ();

        Thread t2 = new Thread(new MyThread2());
        t2.start();
        t2.join ();

        Thread t3 = new Thread(new MyThread3());
        t3.start();
        t3.join ();

        Thread t4 = new Thread(new MyThread4());
        t4.start();
        t4.join ();
    }
→ Ссылка