如何知道Swing中两个线程的完成时间

时间:2014-10-24 18:50:24

标签: java multithreading swing

我必须执行两项任务。我喜欢两个线程同时执行每个任务。任务不共享数据。

在任务开始之前,会显示一个对话框,其中包含“等待,处理......”信息。

这里是代码:

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?

我想在两个线程结束时关闭对话框。如何知道他们什么时候结束?应该何时何地关闭对话框?

更新:线程必须同时运行,而不是顺序模式。

4 个答案:

答案 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();
    }

}