在线程池使用Callable和Runnable的区别以及如何关闭线程
一、区别总结:
- Callable定义的方法是call,而Runnable定义的方法是run。
- Callable的call方法可以有返回值,而Runnable的run方法不能有返回值,这是核心区别。
- Callable的call方法可抛出异常,而Runnable的run方法不能抛出异常。
二、返回值的区别
他们的核心区别是Callable可以返回Feature的对象,这个对象可以了解线程的运行情况,设置可以关闭线程!
三、Runnable代码事例
package com.qunar.synchro; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by qiu.li on 2015/9/21. * 这是一个继承Runnable的例子 */ public class TestRunnable implements Runnable { public static void main(String[] args) { ExecutorService runnableService = Executors.newFixedThreadPool(3); Runnable r1 = new TestRunnable(); runnableService.submit(r1); runnableService.submit(new TestRunnable()); runnableService.submit(new TestRunnable()); runnableService.submit(new TestRunnable()); runnableService.shutdown(); System.out.println("go on"); System.out.println("end"); } @Override public void run() { for(int i=0;i<5; i++) { System.out.println(Thread.currentThread().getName() + ";random:" + (int) (Math.random() * 10 * 1000)); try { Thread.sleep( (int) (Math.random() * 10 * 1000)); } catch (InterruptedException e) { e.printStackTrace(); } } } }
他的输出也比较简单,
pool-1-thread-2;random:9491 go on end pool-1-thread-3;random:6983 pool-1-thread-1;random:718 pool-1-thread-2;random:4214..... Process finished with exit code 0
四、Callable代码
package com.qunar.synchro; import com.sun.org.apache.xalan.internal.utils.FeatureManager; import java.util.concurrent.*; /** * Created by qiu.li on 2015/9/21. */ public class TestCallable implements Callable<Boolean> { int i; public static void main(String[] args) { ExecutorService runnableService = Executors.newFixedThreadPool(3); Future<Boolean> r1 = runnableService.submit(new TestCallable(1)); Future<Boolean> r2 = runnableService.submit(new TestCallable(2)); Future<Boolean> r3 = runnableService.submit(new TestCallable(3)); try { boolean b2 = r2.get(); //r2先跑 boolean b3 = r3.get(); //r3先跑 System.out.println(b2); System.out.println(b3); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } r1.cancel(true);//r1是死循环,现在退出 runnableService.shutdownNow(); } public TestCallable(int i){ this.i = i; } @Override public Boolean call() { try { switch (i){ case 1: while(true) { System.out.println(Thread.currentThread().getName() + ";i:" + this.i); //第一个线程 Thread.sleep(200); } default: Thread.sleep(500); System.out.println(Thread.currentThread().getName() + ";i:" + this.i); //其他线程 } } catch (InterruptedException e) { e.printStackTrace(); } return true; } }
运行的结果:
pool-1-thread-1;i:1 pool-1-thread-1;i:1 pool-1-thread-1;i:1 java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at com.qunar.synchro.TestCallable.call(TestCallable.java:46) at com.qunar.synchro.TestCallable.call(TestCallable.java:10) at java.util.concurrent.FutureTask.run(FutureTask.java:262) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:745) pool-1-thread-2;i:2 pool-1-thread-3;i:3 true true Process finished with exit code 0
大家可以看见抛出的异常,这是因为在线程1被阻塞的时候(比如被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞时),由于没有占用CPU,是不能给自己的中断状态置位的,这就会产生一个InterruptedException异常。