powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Как отследить завершение всех потоков
24 сообщений из 24, страница 1 из 1
Как отследить завершение всех потоков
    #39191930
saxix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Приветствую. Использую класс наследованный от Runnable для создание потоков. Запуск через кнопку. После запуска кнопка становится неактивной. После выполнения всех потоков требуется сделать ее активной. Как отследить завершение всех потоков? Или может посоветуете более продвинутый класс для работы с потоками?
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39191944
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
saxixИспользую класс наследованный от Runnable для создание потоков.
Начинаем с заблуждения. Runnable, так же как и Callable это не "создание потоков". Это реализация определенной задачи, которую вы можете выполнять в разных потоках. Научитесь отделять поток от самой задачи, которую он выполняет.

saxixЗапуск через кнопку. После запуска кнопка становится неактивной.

Swing?

saxixПосле выполнения всех потоков требуется сделать ее активной.

Что мешает?

saxixКак отследить завершение всех потоков?
Ну, если в лоб, то дописать в конце каждого метода run() некий, код. Когда все методы его выполнят, запустить событие активации кнопки. Это может быть атомарный счетчик, при запуске задачи вы его инкрементируете, при завершении, соответственно декрементируете. При обнулении, выполняете нужный вам код.
По-хорошему, конечно, надо открыть для себя ExecutorService и Future.

saxixИли может посоветуете более продвинутый класс для работы с потоками?
SwingWorker либо аналогичный класс для вашего GUI фреймверка.
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39191947
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
saxix,
Что за поток что кнопка не отжалась?
Или это фича свинга?
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39191981
saxix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Petro123saxix,
Что за поток что кнопка не отжалась?
Или это фича свинга?
Я не писал что она не отжалась. Стормозил малость. Подумал что фокус с атомарным счетчиком не пройдет.
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39191983
saxix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz,
попробую ServiceExecutor
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39191999
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
saxixпопробую ServiceExecutor
Ну, изобретете свой SwingWorker в итоге. Так почему бы не взять готовый?
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192009
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
saxixЯ не писал что она не отжалась. Стормозил малость. Подумал что фокус с атомарным счетчиком не пройдет.
Кстати, в JUC есть такой класс.
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html

Проблема только в том, что в GUI нужно не ждать пока что-то закончится, а правильно обрабатывать синхронные колбэки. Поэтому большинство JUC классов не особо полезны.
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192025
WGA
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
WGA
Гость
Если Java 8, то можно воспользоваться CompletableFuture

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
public class Main {

    public static void main(String[] args) throws Exception {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            sleep(1000L);
            return 1;
        });
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            sleep(2000L);
            return 2;
        });
        CompletableFuture<Integer> future3 = CompletableFuture.supplyAsync(() -> {
            sleep(3000L);
            return 3;
        });
        CompletableFuture<Void> together = CompletableFuture.allOf(future1, future2, future3);
        together.get();

        System.out.println(future1.get());
        System.out.println(future2.get());
        System.out.println(future3.get());
    }

    public static void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192026
saxix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowiczsaxixпопробую ServiceExecutor
Ну, изобретете свой SwingWorker в итоге. Так почему бы не взять готовый?
Пытаюсь проанализировать, с чем быстрее реализовать с учетом времени на изучение
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192042
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
WGAЕсли Java 8, то можно воспользоваться CompletableFuture
Код: java
1.
2.
        CompletableFuture<Void> together = CompletableFuture.allOf(future1, future2, future3);
        together.get();


С тем же успехом можно и в цикле по обычным Future блокироваться. Проблема GUI в другом. EDT блокировать нельзя.

Вообще у меня есть ещё одно решение в лоб.
Можно создать новый поток, на него заджоинить все остальные, а в нём просто пульнуть событие в EventQueue. Но это всё равно коряво.
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192050
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
saxixПытаюсь проанализировать, с чем быстрее реализовать с учетом времени на изучение
Покажите что ли код. Потому как концептуально архитектурно нужно вообще всё иначе делать.
Потоки выполняют некую задачу и обновляют модель уже в EDT через SwingWorker. И это уже задача модели определить все ли данные готовы. Задачу как бы от потоков нужно вообще абстрагировать. Не важно ведь сколько там потоков один, или десять, важно, то готова ли модель к тому чтобы активировать кнопку или нет.

Поэтому все извращения с JUC для архитектуры GUI только во вред.
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192063
Сергей Арсеньев
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В общем случае можно сделать некую шину и два события на ней. Кнопка подписывается на события. И при аттачменте посылает первое событие, по которому шедулер отвечает в шину сообщением второго типа с текущим состоянием.
Шедулер так же потоков пуляет второе сообщение и по изменению своего состояния.
Таким образом имеем разное количество кнопок, которые переключают свою доступность по состоянию шедулера.
В таком примитивном варианте несложно делается самим на примитивах, но можно и стандартными методами. :)
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192113
saxix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczsaxixПытаюсь проанализировать, с чем быстрее реализовать с учетом времени на изучение
Покажите что ли код. Потому как концептуально архитектурно нужно вообще всё иначе делать.
Потоки выполняют некую задачу и обновляют модель уже в EDT через SwingWorker. И это уже задача модели определить все ли данные готовы. Задачу как бы от потоков нужно вообще абстрагировать. Не важно ведь сколько там потоков один, или десять, важно, то готова ли модель к тому чтобы активировать кнопку или нет.

Поэтому все извращения с JUC для архитектуры GUI только во вред.
Да я только тестовый накидал, и то уже поправил на ServiceExecutor. Так сказать - пытаюсь понять что написал.
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
package test;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

class Executor {
    private JButton button;

    JButton getButton() {
        return button;
    }

    void setButton(JButton button) {
        this.button = button;
    }

    void task(int id) throws InterruptedException {
        Random random = new Random();
        int timer = random.nextInt(5);
        Thread.sleep(1000 * timer);
        System.out.println("Задача [" + id + "] выполнена: " + new Date());
    }

    void run() throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(8);
        List<Future> futureList = new ArrayList<Future>();

        System.out.println("Кнопка не активна");
        button.setEnabled(false);
        for (int x = 0; x < 10; x++) {
            final int id = x;
            futureList.add(executorService.submit(new Runnable() {
                public void run() {
                    try {
                        task(id);
                    } catch (Throwable e) {
                        e.printStackTrace();
                    }
                }
            }));
        }
        executorService.shutdown();
        executorService.awaitTermination(10, TimeUnit.HOURS);
        System.out.println("Кнопка активна");
        button.setEnabled(true);
    }
}

public class TestButtonEnabled extends JFrame {
    private JButton getButton() {
        JButton button = new JButton("test");
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    Executor executor = new Executor();
                    executor.setButton(button);
                    executor.run();
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }
        });
        return button;
    }

    private static void createAndShowGui() {
        TestButtonEnabled testButtonEnabled = new TestButtonEnabled();
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(testButtonEnabled.getButton());
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui();
            }
        });
    }
}
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192133
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
saxix
Код: java
1.
2.
        executorService.shutdown();
        executorService.awaitTermination(10, TimeUnit.HOURS);


Это вообще не то. Здесь должно быть
Код: java
1.
2.
3.
for (Future f : futureList){
      f.get();         
}



Но, оно для GUI всё равно не подходит, потому что блокирует EDT в обоих случаях.
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192139
saxix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowiczsaxix
Код: java
1.
2.
        executorService.shutdown();
        executorService.awaitTermination(10, TimeUnit.HOURS);


Это вообще не то. Здесь должно быть
Код: java
1.
2.
3.
for (Future f : futureList){
      f.get();         
}



Перед отправкой поменял.
BlazkowiczНо, оно для GUI всё равно не подходит, потому что блокирует EDT в обоих случаях

Что это значит?
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192146
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
saxixЧто это значит?
Это значит что в момент, когда вы будете ждать завершения потоков, вы блокируете текущий поток. А текущий поток это Event Dispatch Thread, на котором работает GUI. Блокировка этого потока приводит к блокировке всего UI и никакого профита от многопоточности не будет. Вы пример разве не запускали? Фриза на секунду разве нет? Обычно после такого сразу начинаются жалобы "Swing тормозит".
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192153
saxix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczsaxixЧто это значит?
Это значит что в момент, когда вы будете ждать завершения потоков, вы блокируете текущий поток. А текущий поток это Event Dispatch Thread, на котором работает GUI. Блокировка этого потока приводит к блокировке всего UI и никакого профита от многопоточности не будет. Вы пример разве не запускали? Фриза на секунду разве нет? Обычно после такого сразу начинаются жалобы "Swing тормозит".
Тормозов, если честно, не заметил. Формочка свободно перетаскивается по экрану
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192162
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
saxix,

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

Можно запустить 1 SwingWorker на каждую задачу.
Можно запустить 1 SwingWorker для все задачи, а внутри doInBackground уже запускать фоновые задачи. Там же и заблокировать SwingWorker ожидая их завершения.
Может вообще нужен ForkJoinPool, если результат фоновых задач нужно собрать воедино.
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192167
saxix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowiczsaxix,

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

Можно запустить 1 SwingWorker на каждую задачу.
Можно запустить 1 SwingWorker для все задачи, а внутри doInBackground уже запускать фоновые задачи. Там же и заблокировать SwingWorker ожидая их завершения.
Может вообще нужен ForkJoinPool, если результат фоновых задач нужно собрать воедино.
Могу только послушать Вашего совета. Попробую реализовать второй вариант
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192171
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
saxix,

И ещё не понятно, с одной стороны у вас Java 8, с другой стороны ни лямбд, ни Diamond Operator я не вижу.
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192179
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
saxixТормозов, если честно, не заметил. Формочка свободно перетаскивается по экрану
Двигает окно операционка. Swing это событие лишь слушает.
Попробуйте изменить размер окна. Попробуйте добавить текстовое поле и вбивать в него текст во время процесса.
В конце концов, добавьте JProgressBar, тогда-то косяки и полезут наружу.
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192184
saxix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowiczsaxix,
И ещё не понятно, с одной стороны у вас Java 8, с другой стороны ни лямбд, ни Diamond Operator я не вижу.
Использование 8-ки не обязательное ж условие на использование лямбд. Могу и переделать.
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192214
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

/**
 * This class represents...
 */
public class AsyncUI {

    static class Model {
        int level;

        public void setLevel(int level) {
            System.out.println(level);
            int old = this.level;
            this.level = level;
            pcs.firePropertyChange("level", old, level);
        }

        public void decrement() {
            setLevel(this.level - 1);
        }

        private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);

        public void addPropertyChangeListener(PropertyChangeListener listener) {
            this.pcs.addPropertyChangeListener(listener);
        }

        public void removePropertyChangeListener(PropertyChangeListener listener) {
            this.pcs.removePropertyChangeListener(listener);
        }
    }

    static class AsyncModelDecrementer extends SwingWorker<Void, Void>{
        private final int time;

        public AsyncModelDecrementer(int x) {
            this.time = x;
        }

        @Override
        protected Void doInBackground() throws Exception {
            Thread.sleep(time * 1000);
            return null;
        }

        @Override
        protected void done() {
            model.decrement();
        }
    }

    static class BackgroundProcessAction extends AbstractAction{

        public BackgroundProcessAction() {
            super("Background Process");
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            int asyncLevel = 10;
            model.setLevel(asyncLevel);
            for (int x = 0; x < asyncLevel; x++) {
                new AsyncModelDecrementer(x).execute();
            }
        }
    }


    static final Model model = new Model();


    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        JButton btn = new JButton(new BackgroundProcessAction());
        JProgressBar progress = new JProgressBar();
        progress.setStringPainted(true);

        //Do not forget to remove listener when UI disposed
        model.addPropertyChangeListener(evt -> {
            Integer newLevel = (Integer) evt.getNewValue();
            boolean inProgress = newLevel > 0;
            btn.setEnabled(!inProgress);
            progress.setString(newLevel.toString());
            progress.setIndeterminate(inProgress);
        });
        model.setLevel(0);

        frame.add(btn, BorderLayout.CENTER);
        frame.add(progress, BorderLayout.SOUTH);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
}




В идеале, конечно, то что в Main тоже должно быть отдельным классом.
...
Рейтинг: 0 / 0
Как отследить завершение всех потоков
    #39192533
saxix
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz,
попытался переделать под свои нужды, упростил
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
package test;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Random;

class Counter {
    private int threadRunCounter;

    public int getThreadRunCounter() {
        return threadRunCounter;
    }

    public void setThreadRunCounter(int threadRunCounter) {
        System.out.println("Запущено процессов: " + threadRunCounter);
        int old = this.threadRunCounter;
        this.threadRunCounter = threadRunCounter;
        pcs.firePropertyChange("threadRunCounter", old, threadRunCounter);
    }

    private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        this.pcs.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        this.pcs.removePropertyChangeListener(listener);
    }

    public void threadClosed() {
        this.setThreadRunCounter(this.threadRunCounter - 1);
    }
}

class MyWorker extends SwingWorker<Void, Void> {
    private Counter counter;
    private String processName;

    public MyWorker(Counter counter, String processName) {
        this.counter = counter;
        this.processName = processName;
    }

    @Override
    protected Void doInBackground() throws Exception {
        Random r = new Random();
        int time = 1000 * r.nextInt(5);
        Thread.sleep(time);
        return null;
    }

    @Override
    protected void done() {
        System.out.println(this.processName + " - done");
        counter.threadClosed();
    }
}

class BackgrProcessAction extends AbstractAction {
    private Counter counter;
    private int threadCount;

    public BackgrProcessAction(int threadCount, Counter counter) {
        this.counter = counter;
        this.threadCount = threadCount;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        counter.setThreadRunCounter(threadCount);
        for (int idx = 0; idx < threadCount; idx++) {
            new MyWorker(counter, "Процесс №" + idx).execute();
        }
    }
}

public class RunnableClass extends JFrame {

    private static final int THREAD_COUNT = 10;

    private static void createAndShowGui() {
        RunnableClass runnableClass = new RunnableClass();
        JFrame frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        Counter counter = new Counter();
        JButton jButton = new JButton(new BackgrProcessAction(THREAD_COUNT, counter));
        jButton.setText("Запуск");
        frame.add(jButton);

        counter.addPropertyChangeListener(evt -> {
            jButton.setEnabled(!((Integer) evt.getNewValue() > 0));
        });


        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui();
            }
        });
    }
}
...
Рейтинг: 0 / 0
24 сообщений из 24, страница 1 из 1
Форумы / Java [игнор отключен] [закрыт для гостей] / Как отследить завершение всех потоков
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]