Я новичок в параллельных вычислениях. Я работаю над Java в Apache Netbeans. Моя недавняя работа была посвящена семафорам с использованием Java-классов Semaphore и Thread. В этом смысле мне пришлось создать программу, которая с помощью индикаторов выполнения имитирует процесс доставки кредитной карты, который зависит от пяти подпроцессов (моделируемых с помощью потоков). Каждый подпроцесс имеет время, которое моделируется в программе, в данном случае с использованием метода сна из потоков. Реализация семафора заключается в постепенном увеличении общей панели в зависимости от других процессов. Если один из них завершен, его можно заполнить на общей панели. Еще следует добавить, что подпроцессы также имеют соответствующие индикаторы выполнения. Моя проблема возникает в классах BarraGeneral и SubProceso, они представляют собой общий процесс и один подпроцесс. В их переопределенных методах запуска я симулирую время и, конечно же, рисую, но этого не происходит. Я могу сказать, что это действительно работает, потому что на консоли вы можете проверить отпечатки, проблема, как я уже сказал, в том, что индикаторы не отражают этот прогресс, он просто меняется от 0% до 100%.
Я пытался решить эту проблему, уменьшив время симуляции сна, но проблема не в этом. Кроме того, я отладил, и столбцы фактически меняют свое значение на каждой итерации.
Код:
package espe.edu.ec.laboratorio1p2;
import java.util.ArrayList;
import java.util.concurrent.Semaphore;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JProgressBar;
/**
*
* @author DARÍO BENAVIDES
*/
public class BarraGeneral extends Thread{
private int id;
private Semaphore aportes;
private ArrayList<Integer> porcentajes;
private int nHilos;
private JProgressBar bar;
BarraGeneral(int id, Semaphore aportes, ArrayList<Integer> porcentajes, int nHilos, JProgressBar bar){
this.id = id;
this.aportes = aportes;
this.porcentajes = porcentajes;
this.nHilos = nHilos;
this.bar = bar;
}
@Override
public void run(){
int a;
for(int i = 0; i < nHilos; i++){
try {
aportes.acquire();
a = bar.getValue();
bar.setValue(a + porcentajes.get(i));
System.out.println(porcentajes.toString());
} catch (InterruptedException ex) {
Logger.getLogger(BarraGeneral.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
package espe.edu.ec.laboratorio1p2;
import java.util.ArrayList;
import java.util.concurrent.Semaphore;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JProgressBar;
import javax.swing.event.ChangeListener;
/**
*
* @author DARÍO BENAVIDES
*/
public class SubProceso extends Thread{
private Semaphore aportes;
private int id;
private int tiempo;
private int porcentaje;
private ArrayList<Integer> porcentajes;
private JProgressBar bar;
SubProceso(Semaphore aportes, int id, int tiempo, int porcentaje, ArrayList<Integer> porcentajes, JProgressBar bar){
this.aportes = aportes;
this.id = id;
this.tiempo = tiempo;
this.porcentaje = porcentaje;
this.porcentajes = porcentajes;
this.bar = bar;
}
@Override
public void run(){
for(int i = 1; i <= 100; i++){
try{
this.sleep(tiempo);
bar.setValue(i);
}catch(InterruptedException ex){
Logger.getLogger(SubProceso.class.getName()).log(Level.SEVERE, null, ex);
}
}
System.out.println(porcentaje);
porcentajes.add(porcentaje);
aportes.release();
}
}
package espe.edu.ec.laboratorio1p2;
import java.util.ArrayList;
import java.util.concurrent.Semaphore;
import javax.swing.JProgressBar;
/**
*
* @author DARÍO BENAVIDES
*/
public class Laboratorio1P2 {
public static void correr(JProgressBar barProgresoGeneral,
JProgressBar barProgreso1, JProgressBar barProgreso2,
JProgressBar barProgreso3, JProgressBar barProgreso4,
JProgressBar barProgreso5) {
int nHilos = 5;
Semaphore aportes = new Semaphore(0);
ArrayList<Integer> porcentajes = new ArrayList<Integer>();
ArrayList<SubProceso> subProcesos = new ArrayList<>();
BarraGeneral barraGeneral = new BarraGeneral(1, aportes, porcentajes, nHilos, barProgresoGeneral);
subProcesos.add(new SubProceso(aportes, 1, 50, 40, porcentajes, barProgreso1));
subProcesos.add(new SubProceso(aportes, 2, 100, 10, porcentajes, barProgreso2));
subProcesos.add(new SubProceso(aportes, 3, 100, 10, porcentajes, barProgreso3));
subProcesos.add(new SubProceso(aportes, 4, 50, 5, porcentajes, barProgreso4));
subProcesos.add(new SubProceso(aportes, 5, 100, 35, porcentajes, barProgreso5));
barraGeneral.start();
for(int i = 0; i < nHilos; i++){
subProcesos.get(i).start();
}
while(barraGeneral.isAlive() || subProcesos.get(0).isAlive() || subProcesos.get(1).isAlive() || subProcesos.get(2).isAlive() ||
subProcesos.get(3).isAlive() || subProcesos.get(4).isAlive()){
}
}
}
При нажатии на кнопку из JFrame я запускаю программу:
private void iniciarActionPerformed(java.awt.event.ActionEvent evt) {
Laboratorio1P2.correr(barProgresoGeneral, barProceso1, barProceso2,
barProceso3, barProceso4, barProceso5);
}
Ваш код должен быть включен в тело вопроса в виде текста, а не ссылки или изображения. Кроме того, код должен представлять собой минимально воспроизводимый пример
У Oracle есть полезное руководство Создание графического интерфейса с помощью Swing . Пропустите раздел «Обучение с использованием среды IDE NetBeans». Обратите особое внимание на Как использовать индикаторы выполнения. раздел. Добавьте в закладки и изучите остальную часть урока позже.
Вы обновляете JProgressBar в потоке, который не является потоком отправки событий (EDT). См. Параллелизм в Swing.
Это выглядит безумием. Тем не менее, у вас есть занятой цикл, который блокирует EDT. while(barraGeneral.isAlive() ||... означает, что edt не может обновиться до тех пор, пока все ваши темы не перестанут возвращать true для «isAlive».




Похоже, что вы нажимаете кнопку, и у вас появляется основной процесс, который отслеживает ваши подпроцессы. По завершении подпроцесса ваш основной процесс обновляется.
Отключите цикл занятости, происходящий на EDT.
while(barraGeneral.isAlive() || subProcesos.get(0).isAlive() || subProcesos.get(1).isAlive() || subProcesos.get(2).isAlive() ||
subProcesos.get(3).isAlive() || subProcesos.get(4).isAlive()){
}
Все, что вы вызываете/используете из EDT, должно завершиться довольно быстро*. Этот занятый цикл блокирует EDT и предотвращает любую перерисовку или обновление.
*При этом есть предостережение, например, ожидание завершения диалога, в котором Swing/awt запускает другое EDT.
Я думаю, это самые маленькие изменения, которые «исправят» вашу проблему. Лично я бы удалил ваш BarraGeneral, так как он вам не нужен как еще одна тема. Измените свой SubProceso на SwingWorker, где метод «run» выполняет работу в фоновом режиме. Затем переопределите метод done, чтобы обновить общий индикатор выполнения. (Это происходит в EDT после завершения фоновой задачи. Там, где должны происходить все обновления индикатора выполнения!)
Спасибо за вашу помощь, я решил проблему, удалив цикл. Я ценю ваши рекомендации и собираюсь их реализовать, а также я читал SwingWorker, это действительно интересно. Причина, по которой я использовал то, что я использовал, заключается в том, что это были инструменты, которые показал нам мой профессор. У меня все еще есть один единственный вопрос: почему вы упоминаете, что моя реализация семафора сломана, потому что теперь, когда я запускаю свою программу, она постепенно заполняет подпанели, и когда одна из них завершена, заполняется общая полоса, поэтому я не знаю если это создает у меня впечатление, правильно это или нет.
@ruper ты прав! Проверил поведение Семафора, ошибся как работает подсчет разрешений. Я обновлю ответ. Я думал, что о нескольких выпусках можно забыть, но они увеличивают разрешения и позволяют вашему циклу продолжаться несколько раз.
Да, точно так же, какacquire() уменьшает, Release() увеличивает разрешения, в любом случае ваша помощь была даже больше, чем мне нужно, я очень ценю ее.
Если вам нужна помощь, вам следует включить свой код в пример. Похоже, ты блокируешь EDT. Вероятно, вам понадобится SwingWorker, а затем вы сможете опубликовать его, чтобы обновить индикатор выполнения, не блокируя EDT.