1. Runnable接口的限制
JDK提供了ExecutorService接口表示线程池,可以通过submit提交一个任务。
ExecutorService executor = Executors.newFixedThreadPool(4);
executor.submit(task);
但这里的task有个问题,因为继承制Runnable,如果希望返回一个结果,只能用result来表示,这样主线程获取结果,就很不方便。
class Task implements Runnable{
public String result; //只能将结果保存到result,再去读取
public void run(){
this.result = longTimeCalculation();
}
}
因此JDK又提供了一个Callable
2. Callable接口
相比Runnable接口,Callable
不需要返回结果 | 需要返回结果 |
Runnable | Callable |
Future
get():返回一个异步执行的结果
get(long timeout, TimeUnit unit):指定一个最长的等待时间
cancel(boolean mayInterruptIfRunning):中断一个异步任务的执行
isDone():判断当前的异步任务是否已经完成
4. 示例
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
class DownloadTask implements Callable<String> {
String url;
public DownloadTask(String url){
this.url = url;
}
public String call() throws Exception {
System.out.println("start download " + url + "...");
URLConnection conn = new URL(this.url).openConnection();
conn.connect();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))){
String s = null;
StringBuilder sb = new StringBuilder();
while ((s = reader.readLine()) != null) {
sb.append(s).append("
");
}
return sb.toString();
}
}
}
public class Main{
public static void main(String[] args) throws Exception{
ExecutorService executor = Executors.newFixedThreadPool(3);
DownloadTask task = new DownloadTask("https://www.sina.com.cn");
Future<String> future = executor.submit(task);
String html = future.get();
System.out.println(html);
executor.shutdown();
}
}
5.总结:
- 需要返回结果,使用Callable;不需要返回结果,使用Runnable
- 提交Callable任务,可以获得一个Future对象
- 可以用Future在将来某个时刻获得结果