ThreadPoolExecutor的陷阱

下面的程序有什么问题吗? 

class DivideNumbersJob implements Runnable {  

    int a,b;  
    public DivideNumbersJob(int a, int b) {  
        this.a = a;  
        this.b = b;  
    }  

    @Override  
    public void run() {  
        int c = a/b;  
        int d = a%b;  
        System.out.format("%d / %d === %d mod %d\n", a, b, c, d);  
    }  
} 

public class TPEDemo {  

    public static void main(String[] args) throws Exception {  
        ThreadPoolExecutor e = new ThreadPoolExecutor(5, 5, 0,  
                TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());            

        // 但是,与上一篇文章不同,我怕这些作业耗时太多,  
        // 我改用了submit方法,并保留了他们的Future对象。  
        Future<?> f1 = e.submit(new DivideNumbersJob(6, 2));  

        Future<?> f2 = e.submit(new DivideNumbersJob(12, 5));  

        Future<?> f3 = e.submit(new DivideNumbersJob(4, 0)); // 错误的作业!  

        Future<?> f4 = e.submit(new DivideNumbersJob(100, 3));        

        // 告诉Executor,没有更多的任务了。  
        e.shutdown();            

        // 主线程睡一觉  
        Thread.sleep(2000);            

        // 遍历所有的Future对象,如果有没做完的,就取消。  
        for (Future<?> f : new Future<?>[]{f1,f2,f3,f4}) {  
            if(!f.isDone()) {  
                f.cancel(true);  
            }  
        }         
    }  
}  

我提交了一个错误的作业:new DivideNumbersJob(4, 0)。除数不能为0,按照常理,这个作业应该会抛出ArithmeticException。但是这是一个RuntimeException,不用在方法的throws部分声明。所以,DivideNumbersJob这个类仍然可以说是“实现了Runnable接口”(如果加上throws ArithmeticException),则编译通不过,原因是与接口的throws部分不匹配。

但是,实际的执行结果仅仅是如下: 
 

6 / 2 === 3 mod 0 
 100 / 3 === 33 mod 1 
 12 / 5 === 2 mod 2 

没有任何异常!没有任何异常!!控制台干干净净!!! 

修改代码:

 // 主线程睡一觉  

 Thread.sleep(2000);           

 // 遍历所有的Future对象,如果有没做完的,就取消。  

  for (Future<?> f : new Future<?>[]{f1,f2,f3,f4}) {  
      if(!f.isDone()) {  
           f.cancel(true);  
     } else {  
          Object result = f.get();  
      }  
   }  

判断一下:如果未完成,取消作业;如果完成了,试着获取它的值。我们知道,submit提交Runnable作业,返回值一定是null。但是,如果该作业执行期间有异常,那么,当我们试图调用f.get()方法,获取值的时候,将会抛出ExecutionException。 

这是现在执行的结果: 

12 / 5 === 2 mod 2 
6 / 2 === 3 mod 0 
100 / 3 === 33 mod 1 
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero 
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:252) 
at java.util.concurrent.FutureTask.get(FutureTask.java:111) 
at tpe2.TPEDemo.main(TPEDemo.java:44) 
Caused by: java.lang.ArithmeticException: / by zero 
at tpe2.DivideNumbersJob.run(TPEDemo.java:15) 
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) 
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) 
at java.util.concurrent.FutureTask.run(FutureTask.java:166) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) 
at java.lang.Thread.run(Thread.java:636) 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值