我必须执行两项任务。我喜欢两个线程同时执行每个任务。任务不共享数据。
在任务开始之前,会显示一个对话框,其中包含“等待,处理......”信息。
这里是代码:
final JDialog dialog = new JDialog(this, true);
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
// Do the job
return null;
}
@Override
protected void done() {
// Must close dialog? The other finished?
}
};
SwingWorker<Void, Void> worker2 = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
// Do the job
return null;
}
@Override
protected void done() {
// Must close dialog? The other finished?
}
};
worker.execute();
worker2.execute();
dialog.setVisible(true);
// Must close dialog?
我想在两个线程结束时关闭对话框。如何知道他们什么时候结束?应该何时何地关闭对话框?
更新:线程必须同时运行,而不是顺序模式。
答案 0 :(得分:2)
CountDownLatch
,设置为2
SwingWorkers
,将每个引用传递给CountDownLatch
。在done
方法中,在锁存器上调用countDown
。在done
方法中执行此操作,因为无论doInBackground
方法如何退出(例如,如果它抛出Exception
)SwingWorker
,在此工作程序中传递对CountDownLatch
的引用,等待doInBackground
方法中的锁存。调用此SwingWorker
完成方法后,您现在应该能够安全地处理该对话框答案 1 :(得分:0)
我会使用像计数锁这样的东西。它绝对是使用尽可能少的资源。下面的类是计数锁。基本上,您使用构造函数初始化它并指定您需要等待的线程数。
在完成设置后,在主线程(或UI线程)中调用“waitForAll()”。你可以看到waitForAll基本上是在等待来自任何其他线程的通知。如果收到通知,则检查活动工作人员的数量是否已达到零。如果活跃工人的数量仍然大于0,则会再次等待。
然而,工作人员在锁上调用unlock()。 Notify将计数器减1并调用notify(),使主线程唤醒并执行上述过程。
public class CountingLock {
private int counter;
/**
* Number of workers
*
* @param n
*/
public CountingLock(int n) {
this.counter = n;
}
/**
* Wait until counter == 0
* @throws InterruptedException
*/
public synchronized void waitForAll() throws InterruptedException {
while(counter > 0) {
this.wait();
}
}
/**
* Deduce counter and notify
*/
public synchronized void unlock() {
this.counter--;
this.notify();
}
}
在启动线程之前的对话框中执行以下操作:
CountingLock lock = new CountingLock(2);
/** put your thread setup code from your example here */
lock.waitForAll();
dialog.setVisible(false);
确保将锁的引用传递给您的线程,并在每个线程的末尾调用以下内容:
lock.unlock();
根据对此答案的评论,Java从Java 1.5(已验证)提供了一个类java.concurrent.CountDownLatch,具有完全相同的行为。该用法已在API中详细记录。
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html
CoundDownLatch的示例
CountDownLatch lock = new CountDownLatch(2);
/** put your thread setup code from your example here */
lock.await();
dialog.setVisible(false);
在线程中执行以下操作:
lock.countDown();
完整示例
final CountingLock lock = new CountingLock(2);
final JDialog dialog = new JDialog(this, true);
SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
// Do the job
return null;
}
@Override
protected void done() {
// Must close dialog? The other finished?
lock.unlock();
}
};
SwingWorker<Void, Void> worker2 = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
// Do the job
return null;
}
@Override
protected void done() {
// Must close dialog? The other finished?
lock.unlock();
}
};
worker.execute();
worker2.execute();
dialog.setVisible(true);
lock.waitForAll();
dialog.setVisible(false);
实际上你也应该考虑在另一个后台线程中移动waitForAll或await调用并设置dialog.setVisible(false),因为你很可能不希望UI停止。
答案 2 :(得分:0)
你应该call get()两个工人
答案 3 :(得分:0)
现在我已经制作了一个示例代码,可以帮助您理解这背后的逻辑。
import java.awt.BorderLayout;
import javax.swing.*;
public class DemoTest {
JFrame frame = new JFrame();
JLabel lbl1 = new JLabel();
JLabel lbl2 = new JLabel();
SwingWorker<Void,Void> worker1 = new SwingWorker<Void,Void>()
{
@Override
protected Void doInBackground() throws Exception {
for(int i = 0;i<=100;i++)
{
lbl1.setText("Counter1 Value:"+Integer.toString(i));
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}
return null;
}
@Override
protected void done()
{
lbl1.setText("Thread 1 completed its job");
worker2.execute();
}
};
SwingWorker<Void,Void> worker2 = new SwingWorker<Void,Void>()
{
@Override
protected Void doInBackground() throws Exception {
for(int i = 0;i<=100;i++)
{
lbl2.setText("Counter1 Value:"+Integer.toString(i));
try
{
Thread.sleep(100);
}
catch(Exception e)
{
e.printStackTrace();
}
}
return null;
}
@Override
protected void done()
{
lbl2.setText("Thread 2 completed its job");
}
};
public DemoTest()
{
frame.setSize(400,400);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(lbl1,BorderLayout.NORTH);
frame.add(lbl2,BorderLayout.SOUTH);
frame.setVisible(true);
try
{
worker1.execute();
}
catch(Exception e)
{
e.printStackTrace();
}
//close dialog box
}
public static void main(String []args)
{
DemoTest d = new DemoTest();
}
}