探索并发编程(五)------Java多线程开发技巧

发表于:2011-9-27 09:33

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:cutesource    来源:51Testing软件测试网采编

  当然,在有些业务里确实需要一定的依赖性,比如调用者需要得到线程完成后结果,传统的Thread是不便完成的,因为run方法无返回值,只能通过一些共享的变量来传递结果,但在Executor框架里可以通过Future和Callable实现需要有返回值的任务,当然线程的异步性导致需要有相应机制来保证调用者能等待任务完成,关于Future和Callable的用法见下面的实例就一目了然了:

  • public class FutureRenderer {  
  •     private final ExecutorService executor = ...;  
  •     void renderPage(CharSequence source) {  
  •         final List<ImageInfo> imageInfos = scanForImageInfo(source);  
  •         Callable<List<ImageData>> task =  
  •                 new Callable<List<ImageData>>() {  
  •                     public List<ImageData> call() {  
  •                         List<ImageData> result  
  •                                 = new ArrayList<ImageData>();  
  •                         for (ImageInfo imageInfo : imageInfos)  
  •                             result.add(imageInfo.downloadImage());  
  •                         return result;  
  •                     }  
  •                 };  
  •         Future<List<ImageData>> future =  executor.submit(task);  
  •         renderText(source);  
  •         try {  
  •             List<ImageData> imageData =  future.get();  
  •             for (ImageData data : imageData)  
  •                 renderImage(data);  
  •         } catch (InterruptedException e) {  
  •             // Re-assert the thread's interrupted status   
  •             Thread.currentThread().interrupt();  
  •             // We don't need the result, so cancel the task too   
  •             future.cancel(true);  
  •         } catch (ExecutionException e) {  
  •             throw launderThrowable(e.getCause());  
  •         }  
  •     }  
  • }
  •   以上代码关键在于List<ImageData> imageData = future.get();如果Callable类型的任务没有执行完时,调用者会阻塞等待。不过这样的方式还是得谨慎使用,很容易造成不良设计。另外对于这种需要等待的场景,就需要设置一个最大容忍时间timeout,设置方法可以在 future.get()加上timeout参数,或是再调用ExecutorService.invokeAll 加上timeout参数

      线程的取消与关闭

      一般的情况下是让线程运行完成后自行关闭,但有些时候也会中途取消或关闭线程,比如以下情况:

      ● 调用者强制取消。比如一个长时间运行的任务,用户点击“cancel”按钮强行取消

      ● 限时任务

      ● 发生不可处理的任务

      ● 整个应用程序或服务的关闭

      因此需要有相应的取消或关闭的方法和策略来控制线程,一般有以下方法:

      1)通过变量标识来控制

      这种方式比较老土,但使用得非常广泛,主要缺点是对有阻塞的操作控制不好,代码示例如下所示:

  • public class PrimeGenerator implements Runnable {  
  •      @GuardedBy("this")  
  •      private final List<BigInteger> primes  
  •              = new ArrayList<BigInteger>();  
  •      private  volatile boolean cancelled;  
  •      public void run() {  
  •          BigInteger p = BigInteger.ONE;  
  •          while (!cancelled ) {  
  •              p = p.nextProbablePrime();  
  •              synchronized (this) {  
  •                  primes.add(p);  
  •              }  
  •          }  
  •      }  
  •      public void cancel() { cancelled = true;  }  
  •      public synchronized List<BigInteger> get() {  
  •          return new ArrayList<BigInteger>(primes);  
  •      }  
  • }
  • 32/3<123>
    《2023软件测试行业现状调查报告》独家发布~

    关注51Testing

    联系我们

    快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

    法律顾问:上海兰迪律师事务所 项棋律师
    版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
    投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

    沪ICP备05003035号

    沪公网安备 31010102002173号