说说Runnable与Callable
Callable接口:
1 public interface Callable<V> { 2 V call() throws Exception; 3 }
Runnable接口:
public interface Runnable { public abstract void run(); }
相同点:
- 两者都是接口;(废话)
- 两者都可用来编写多线程程序;
- 两者都需要调用Thread.start()启动线程;
不同点:
- 两者最大的不同点是:实现Callable接口的任务线程能返回执行结果;而实现Runnable接口的任务线程不能返回结果;
- Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;
注意点:
- Callable接口支持返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取‘将来’结果;当不调用此方法时,主线程不会阻塞!
Callable工作的Demo:
1 package com.callable.runnable; 2 3 import java.util.concurrent.Callable; 4 import java.util.concurrent.ExecutionException; 5 import java.util.concurrent.FutureTask; 6 7 /** 8 * Created on 2016/5/18. 9 */ 10 public class CallableImpl implements Callable<String> { 11 12 public CallableImpl(String acceptStr) { 13 this.acceptStr = acceptStr; 14 } 15 16 private String acceptStr; 17 18 @Override 19 public String call() throws Exception { 20 // 任务阻塞 1 秒 21 Thread.sleep(1000); 22 return this.acceptStr + " append some chars and return it!"; 23 } 24 25 26 public static void main(String[] args) throws ExecutionException, InterruptedException { 27 Callable<String> callable = new CallableImpl("my callable test!"); 28 FutureTask<String> task = new FutureTask<>(callable); 29 long beginTime = System.currentTimeMillis(); 30 // 创建线程 31 new Thread(task).start(); 32 // 调用get()阻塞主线程,反之,线程不会阻塞 33 String result = task.get(); 34 long endTime = System.currentTimeMillis(); 35 System.out.println("hello : " + result); 36 System.out.println("cast : " + (endTime - beginTime) / 1000 + " second!"); 37 } 38 }
测试结果:
hello : my callable test! append some chars and return it! cast : 1 second! Process finished with exit code 0
Runnable工作的Demo:
1 package com.callable.runnable; 2 3 /** 4 * Created on 2016/5/18. 5 */ 6 public class RunnableImpl implements Runnable { 7 8 public RunnableImpl(String acceptStr) { 9 this.acceptStr = acceptStr; 10 } 11 12 private String acceptStr; 13 14 @Override 15 public void run() { 16 try { 17 // 线程阻塞 1 秒,此时有异常产生,只能在方法内部消化,无法上抛 18 Thread.sleep(1000); 19 } catch (InterruptedException e) { 20 e.printStackTrace(); 21 } 22 // 最终处理结果无法返回 23 System.out.println("hello : " + this.acceptStr); 24 } 25 26 27 public static void main(String[] args) { 28 Runnable runnable = new RunnableImpl("my runable test!"); 29 long beginTime = System.currentTimeMillis(); 30 new Thread(runnable).start(); 31 long endTime = System.currentTimeMillis(); 32 System.out.println("cast : " + (endTime - beginTime) / 1000 + " second!"); 33 } 34 }
测试结果:
cast : 0 second! hello : my runable test! Process finished with exit code 0
写此篇的原因是一次面试中问到Callable与Runnable的区别,当时用的多的是Runnable,而Callable使用很少!
比较了两者后(网上查了不少),发现Callable在很多特殊的场景下还是很有用的!最后留点抄的代码,加深对Callable的认识!
1 package com.inte.fork; 2 3 /** 4 * Created on 2016/4/20. 5 */ 6 7 import java.util.*; 8 import java.util.concurrent.*; 9 10 import static java.util.Arrays.asList; 11 12 public class Sums { 13 14 static class Sum implements Callable<Long> { 15 private final long from; 16 private final long to; 17 18 Sum(long from, long to) { 19 this.from = from; 20 this.to = to; 21 } 22 23 @Override 24 public Long call() { 25 long acc = 0; 26 for (long i = from; i <= to; i++) { 27 acc = acc + i; 28 } 29 System.out.println(Thread.currentThread().getName() + " : " + acc); 30 return acc; 31 } 32 } 33 34 public static void main(String[] args) throws Exception { 35 ExecutorService executor = Executors.newFixedThreadPool(3); 36 List<Future<Long>> results = executor.invokeAll(asList( 37 new Sum(0, 10), new Sum(0, 1_000), new Sum(0, 1_000_000) 38 )); 39 executor.shutdown(); 40 41 for (Future<Long> result : results) { 42 System.out.println(result.get()); 43 } 44 } 45 }
本文转自:https://www.cnblogs.com/frinder6/p/5507082.html