Каковы будут последствия запуска нескольких потоков, подобных этому? - PullRequest
0 голосов
/ 07 января 2019

Мне нужно запустить 2 потока одновременно (иногда, если оба были запрошены вместе), в противном случае, если один из них запрашивается в одиночку, тогда каждый поток должен работать самостоятельно. Каждый поток будет нести ответственность за получение своего уникального чтения от своего собственного уникального преобразователя (фактического оборудования), мне нужно, чтобы каждый поток запрашивал свой преобразователь, пока не будет обнаружено определенное значение. Если и только если это значение обнаружено, поток должен остановиться и выйти.

Мне также нужен способ, чтобы мое программное обеспечение без сомнения знало, что оба потока остановились, завершили / завершили свою задачу и обнаружили соответствующие значения из аппаратного обеспечения. Если и только если оба потока обнаруживают свои значения, должен вызываться мой метод onFinish (). В моем коде я использовал третий поток для этого мониторинга и использования целочисленных значений. Целочисленная переменная threadCount сбрасывается в 0 после вызова моего метода onFinish (), как и мой логический логин shouldRun, который сбрасывается в false в методе onFinish ().

Интересно, является ли мой подход приемлемым / логичным (пожалуйста, обратите внимание, что я еще не выполнил логику для фактического запроса каждого преобразователя (вероятно, будет использовать цикл while)) и каковы последствия использования подхода, который я описал, мой код как показано ниже:

private void decreaseThreadCount(){
    threadCount -=1;
}

boolean shouldRun = false;
int threadCount = 0;

public void onStart() {
    System.out.println("START");
    System.out.println("    ");
    System.out.println("START PROGRESS BAR");

    if((customProgressBarL != null || customProgressBarR != null) || (customProgressBarL != null && customProgressBarR != null)){
        shouldRun = true;
    }

    /**TESTING PURPOSES*/

    if (customProgressBarL != null) {
        threadCount += 1;
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 100; i++) {
                    try {
                        customProgressBarL.updateProgress(i);
                        customProgressBarL.repaint();
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                try {
                    Thread.sleep(5);
                    decreaseThreadCount();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }

        }).start();
    }

    if (customProgressBarR != null) {
        threadCount += 1;
        new Thread(new Runnable() {
            @Override
            public void run() {

                for (int i = 0; i <= 100; i++) {
                    try {
                        customProgressBarR.updateProgress(i);
                        customProgressBarR.repaint();
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //System.out.println("Thread Count: " + threadCount);
                try {
                    Thread.sleep(5);
                    decreaseThreadCount();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }).start();
    }

    new Thread(new Runnable() {
        @Override
        public void run() {

            while(threadCount >= 0 && shouldRun){
                try {
                    System.out.println("Thread Count: " + threadCount);
                    if(threadCount == 0){
                        onFinish();
                        return;
                    }
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return;
        }
    }).start();

}

[Edit 1] После прочтения приведенных советов и множества онлайн-документации я пришел к следующему коду, который, кажется, работает в случаях, которые я до сих пор тестировал.

Интересно, стоит ли мне по-прежнему использовать SwingWorkers или приемлем ли измененный подход?

public void onStart() {
    System.out.println("START");
    System.out.println("    ");
    System.out.println("START PROGRESS BAR");

    /**TESTING PURPOSES*/
    CountDownLatch countDownLatch = new CountDownLatch(2);
    new Thread(new Runnable() {
        @Override
        public void run() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    if (customProgressBarL != null) {
                        for (int i = 0; i <= 100; i++) {
                            try {
                                customProgressBarL.updateProgress(i);
                                customProgressBarL.repaint();
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    countDownLatch.countDown();
                    return;
                }
            }).start();

            new Thread(new Runnable() {
                @Override
                public void run() {         
                    if(customProgressBarR != null){
                        for (int i = 0; i <= 100; i++) {
                            try {
                                customProgressBarR.updateProgress(i);
                                customProgressBarR.repaint();
                                Thread.sleep(50);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    countDownLatch.countDown();
                    return;
                }
            }).start();
            try{
                countDownLatch.await();
                onFinish();
            } catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }).start();
}

[Редактировать 2]

Я попробовал версию, в которой я использую SwingWorker вместо своих потоков, ниже приведен код, и он работает так же, как и код в [Правка 1] (насколько я могу судить по крайней мере). Каковы плюсы / минусы каждого подхода?

 private class MySwingWorker extends SwingWorker<Object, Object> {

    CountDownLatch countDownLatch;
    JCustomProgressBar progressBar;

    public MySwingWorker(CountDownLatch countDownLatch, JCustomProgressBar progressBar){
        this.countDownLatch = countDownLatch;
        this.progressBar = progressBar;
    }

    @Override
    protected Object doInBackground() throws Exception {
        if(progressBar != null){
            for (int i = 0; i <= 100; i++) {
                try {
                    progressBar.updateProgress(i);
                    progressBar.repaint();
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        countDownLatch.countDown();
        return null;
    }
}

private class MySwingWorkerManager extends SwingWorker<Object, Object> {

    CountDownLatch countDownLatch;

    @Override
    protected Object doInBackground() throws Exception {
        this.countDownLatch = new CountDownLatch(2);
        new MySwingWorker(countDownLatch, customProgressBarL).execute();
        new MySwingWorker(countDownLatch, customProgressBarR).execute();
        try{
            countDownLatch.await();
            onFinish();
        } catch (InterruptedException e){
            e.printStackTrace();
        }
        return null;
    }
}

Я инициирую все следующим образом в моем методе onStart (), вызывая метод execute ():

public void onStart() {
    System.out.println("START");
    System.out.println("    ");
    System.out.println("START PROGRESS BAR");

    System.out.println("customProgressBarL is: "+customProgressBarL);
    System.out.println("customProgressBarR is: "+customProgressBarR);

    /**TESTING PURPOSES*/
    new MySwingWorkerManager().execute();
}

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Только один поток должен иметь доступ к компонентам качания; вы должны написать что-то вроде этого:

SwingUtilities.invokeLater(() -> {
    customProgressBarR.updateProgress(i);
    customProgressBarR.repaint();
});
0 голосов
/ 07 января 2019

Вы инициировали все потоки, которые одновременно находятся снаружи (T1, T2, T3), и T3 ожидает завершения всех из них и выполнения некоторого onFinish.

Вместо этого вы можете создавать экземпляры T1 и T2 внутри T3. Создать отсчет с номером счета. Уменьшите счетчик защелок, когда оба потока завершат свою задачу, а затем выполните onFinish ().

Вся логика для создания T1 / T2 должна быть внутри T3.

new Thread(new Runnable() {
    @Override
    public void run() {
      int count = 2;
      CountdownLatch latch = new CountdownLatch(count);
      MyThread t1 = new MyThread(latch);
      MyThread t2 = new MyThread(latch);
      t1.start()
      t2.start();
      latch.await();
      onFinish();
    }
}).start();
...