这就是事情的发展:我有一个Java应用程序主窗口的Jframe,其中包含一个带有多个Jprogressbar的面板。我想为每个Jprogressbar启动一个线程,该线程将自己启动另一个线程。当任何"次级"线程完成时,我想在我的Jframe中更新Jprogressbar。此外,在安排所有这些内容之前,由于我不希望用户能够单击Jframe上的任何内容,因此我还希望在Jframe中设置某些按钮。容易?
ActivarBotones abFalse = new ActivarBotones(false);
abFalse.start();
try {
abFalse.join();
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
EstablecerConexiones ec = new EstablecerConexiones();
ec.start();
try {
ec.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ActivarBotones abTrue = new ActivarBotones(true);
abTrue.start();
两个问题。
如果我从上方运行代码,则没有任何更新。如果我只启动EC线程,一切几乎都正确。
我对同步不了解,不知道该怎么做才能同时启动所有"主要"线程。
有线索?
这是一个少量样本,我认为它没有回答您的所有问题,但它证明了基本概念(有一个生病的妻子,请照顾一个6个月大,并与一只手:p)
public class ThreadedProgress {
public static void main(String[] args) {
new ThreadedProgress();
}
public ThreadedProgress() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JPanel progressPane = new JPanel(new GridBagLayout());
JProgressBar progressBar = new JProgressBar(0, 100);
progressPane.add(progressBar);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(progressPane);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
new Thread(new MainThread(progressBar)).start();
}
});
}
public interface CallBack {
public void done(Runnable runnable);
}
public static class MainThread implements CallBack, Runnable {
public static final Object UPDATE_LOCK = new Object();
public static final Object WAIT_LOCK = new Object();
private List<Runnable> running = new ArrayList<>(25);
private List<Runnable> completed = new ArrayList<>(25);
private final JProgressBar progressBar;
public MainThread(JProgressBar progressBar) {
this.progressBar = progressBar;
}
@Override
public void done(Runnable runnable) {
synchronized (UPDATE_LOCK) {
running.remove(runnable);
completed.add(runnable);
}
int count = running.size() + completed.size();
updateProgress(completed.size(), count);
synchronized (WAIT_LOCK) {
WAIT_LOCK.notify();
}
}
protected void updateProgress(final int value, final int count) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
int progress = Math.round(((float) value / (float) count) * 100f);
progressBar.setValue(progress);
}
});
}
@Override
public void run() {
for (int index = 0; index < 5; index++) {
ChildSpawn spawn = new ChildSpawn(this);
running.add(spawn);
}
for (Runnable runnable : running) {
new Thread(runnable).start();
}
while (running.size() > 0) {
synchronized (WAIT_LOCK) {
try {
WAIT_LOCK.wait();
} catch (InterruptedException ex) {
}
}
}
System.out.println("I'm all done");
}
}
public static class ChildSpawn implements Runnable {
private CallBack callBack;
public ChildSpawn(CallBack callBack) {
this.callBack = callBack;
}
@Override
public void run() {
try {
Thread.sleep((long)Math.round(Math.random() * 5000));
} catch (InterruptedException ex) {
}
callBack.done(this);
}
}
}
ActivarBotones
线程未完成。
如果您不运行该线程时起作用,则该线程中的某些内容未完成。否则,它将通过EstablecerConexiones
线程。由于启动该线程后,您在此线程上调用.join()
,因此在该线程完成之前,代码不会继续。因此,其中一定有些东西在循环中被阻塞或捕获。
以调试模式运行您的应用程序,并在ActivarBotones
线程中放置断点。追踪它,看看为什么它没有完成。
对于您的第二个问题,如果您启动每个主线程,但不要加入它们,直到它们全部启动,它们都会同时运行。当然,这大大简化了事情。许多人更喜欢使用执行器服务来控制其线程。您还必须担心线程安全实现,因此您不会遇到同步问题。最后,如果您正在与秋千组件进行互动,则所有这些都需要在专用事件派遣线程上完成。