浏览 3078 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-05-30
最后修改:2009-06-11
关于这一点,Sun Forum 里有一个帖子与此相关。这个帖子的楼主最后给出了一个会破坏 cancel(boolean) 方法语义约定的解决方案。我个人觉得还有改进的余地。可以不去干扰 cancel 和 isDone 方法的实现,转而去添加一个新方法 await。在这个方法里实现我们需要的功能:不管任务执行过程当中发生了什么(比如用户取消),只有当 run 方法真正返回时这个方法才返回。如果需要无阻塞的探测方法,可以再添加一个 isDead。 public class FutureTask2<V> extends FutureTask<V> { public FutureTask2(Callable<V> callable) { super(callable); } public FutureTask2(Runnable runnable, V result) { super(runnable, result); } public void await() throws InterruptedException { finishLatch.await(); } public void await(long timeout, TimeUnit unit) throws InterruptedException { finishLatch.await(timeout, unit); } public boolean isDead() { return finishLatch.getCount() == 0; } @Override public void run() { try { super.run(); } finally { finishLatch.countDown(); } } private final CountDownLatch finishLatch = new CountDownLatch(1); } 同样的问题也存在于 SwingWorker 中,而且这个问题更加棘手。因为 NetBeans 附带的 appframework 就使用了 SwingWorker 作为 Task 的实现基类(尽管 appframework 把 SwingWorker 单独抽到一个包里了,但其实它的源码跟 JDK6 里面的一样)。如果你使用 appframework 提供的 Task 来处理 Swing 的异步任务的话,那么在感觉很爽的同时也会为这个 isDone 的问题而头疼。只有当我们的后台方法能很快的检测到任务被取消了,并且能很快地完成任务的退出,否则我们就有麻烦了。如果任务没有办法立刻取消,那么我们会看到 Task 的状态是已完成并且是已取消,但是后台线程还在工作。而且我们还没有任何的办法知道后台线程是不是真的死掉了。因为 Thread 类实例被 Task 类通过 FutureTask 给包裹起来了。 但是 SwingWorker 把 run() 方法做成 final 了。所以连带 Task 也没办法找到一个合适的解决方案。如果您恰好对此感兴趣,欢迎探讨! 补 我的思路一直局限在 run 方法上。如果我们在 SwingWorker 的 doInBackground() 里面来做应该可以达到目的的。一样的道理,这也应该适用于 Task。SwingWorker 的解决代码: public class MySwingWorker extends SwingWorker<Void, Void> { public void await() throws InterruptedException { finishLatch.await(); } public void await(long timeout, TimeUnit unit) throws InterruptedException { finishLatch.await(timeout, unit); } public boolean isDead() { return finishLatch.getCount() == 0; } @Override protected Void doInBackground() throws Exception { try { Thread.sleep(1000); // 模拟耗时工作 } finally { finishLatch.countDown(); } return null; } private final CountDownLatch finishLatch = new CountDownLatch(1); } 也许有人会有疑问,无论是在前面的 FutureTask2 还是这里的 MySwingWorker,在锁上调用 countDown() 的时候都没有做检查。如果 FutureTask2 或者 MySwingWorker 被重复调用怎么办,是不是会导致锁的状态被破坏?不会的。因为 FutureTask 这个基类会保证如果重复调用 run(),那么第二次以及后续的调用都不会触发 FutureTask 所包裹的 Callable 或者 Runnable。也就是说 FutureTask 会安静地忽略除了第一次以外的调用。一样地,SwingWorker 也忽略除了第一次以外的调用。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |