关于多线程Callable和Future

来源:互联网 发布:微软亚洲研究院 知乎 编辑:程序博客网 时间:2024/06/05 09:02
---------------------- android培训、java培训、期待与您交流! ---------------------- 关于多线程Callable和Future        实现多线程我们可以继承Thread类或者实现Runnable接口,通过Thread类把run()方法包装成线程执行体,但是这两种方法都不能直接把任意方法直接包装成线程执行体,比如说一个带返回值的方法,或者一个抛异常的方法。        从Java 5开始,Java提供了Callable接口,该接口是Runnable接口的增强版,Callable接口提供了一个call()方法,可以作为线程执行体,但call()方法比run()方法的功能更强大。call()方法可以有返回值。call()方法可以声明抛出异常。因此我们完全可以提供一个Callable对象作为Thread的target,而该线程的线程执行体就是Callable对象的call()方法。       通过查阅API发现,Callable接口是java 5新增的接口,而他不是Runnable接口的子接口,所以Callable对象不能直接作为Thread类的target。而且Callable方法还有一个返回值——call()方法,不能直接调用,它是作为线程执行体才被调用的。             在工具开发包中,java 5 提供了Future接口来代表Callable接口里的call()方法的返回值,并且为Future接口提供了一个FutureTask实现类,该实现类实现了Future接口,并且实现了Runnable接口——可以作为Thread类的target。实际上这里的FutureTask类实现了一个桥梁的作用,用于连接Callable对象和Thread对象。需要注意的是Callable接口有泛型限制,Callable接口里的泛型形参类型,与call()方法的返回值类型相同。接口 Callable<V>V call() throws Exception 计算结果,如果无法计算结果,则抛出一个异常。类 FutureTask<V>  V - 此 FutureTask 的 get 方法所返回的结果类型。public V get() throws InterruptedException,ExecutionException 如有必要,等待计算完成,然后获取其结果。创建并启动有返回值的线程步骤与实现Runnable接口相似:1.创建Callable接口的实现类,并实现call()方法2.创建Callable实现类的实例,使用FutureTask类来包装Callable对象3.使用FutrueTask对象作为Thread对象的target创建并启动新线程。4.调用FutrueTask对象的get()方法来获得子线程执行结束后的返回值。例:[java] view plain copyimport java.util.concurrent.Callable;  import java.util.concurrent.FutureTask;    public class ThirdThread implements Callable<Integer>{      public Integer call(){          int i = 0;          for( ; i<60; i ++){              System.out.println(Thread.currentThread().getName() + "循环变量i的值是 : " + i);          }          return i;      }            public static void main(String[] args) {                    ThirdThread rt = new ThirdThread(); //创建Callable对象          FutureTask<Integer> task = new FutureTask<Integer>(rt);//使用FutrueTask来包装Callable对象          for(int i=0 ; i<60 ; i++){              System.out.println(Thread.currentThread().getName() + "-------" + i);              if(i == 10){                  new Thread(task, "有返回值的线程").start(); //实际上还是以Callable对象创建并启动线程              }          }          try{              System.out.println("子线程的返回值 :" + task.get());          }          catch(Exception e){              e.printStackTrace();          }      }  }   总结:         通过继承Thread类或实现Runnable、Callable接口都可以实现多线程,不过实现Runnable接口与实现Callable接口的方式基本相同,只是Callable接口里定义的方法有返回值,可以声明抛出异常而已。采用实现Runnable、Callable接口的方式创建多线程,线程类只是实现了Runnable接口或Callable接口,还可以继承其他类在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将 CPU、代码和数据分开,形成清晰的模型,较好的体现了面向对象的思想。 个人理解:可以把Thread类理解成代工厂,而Runnable接口则是原材料,工厂只负责将符合标准的原材料加工成成品,而Callable接口则是另一种材料,他需要先被FutrueTask加工成半成品(即符合Runnable标准的材料),然后在交给Thread工厂加工。


再加上一个自己写的例子

package cn.I.Calls;


import java.util.Date;
import java.util.concurrent.Callable;


public class Calls implements Callable<Object> {
private String taskNum;


Calls(String taskNum) {
this.taskNum = taskNum;
}


public Object call() throws Exception {
System.out.println(">>>" + taskNum + "任务启动");
Date dateTmp1 = new Date();
Thread.sleep(1000);
Date dateTmp2 = new Date();
long time = dateTmp2.getTime() - dateTmp1.getTime();
System.out.println(">>>" + taskNum + "任务终止");
return taskNum + "任务返回结果,当前任务时间" + time + "毫秒";
}


}


package cn.I.Calls;


import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


public class Test {


/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
System.out.println("程序开始运行-----");
Date date1 = new Date();
int taskSize = 5;
// 创建一个线程池
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
List<Future> list = new ArrayList<Future>();
for (int i = 0; i < taskSize; i++) {
Callable c = new Calls(i + "  ");
// 执行任务并获取Future对象
Future f = pool.submit(c);
list.add(f);
}
// 关闭线程池
pool.shutdown();
// 获取所有并发任务的运行结果
for (Future f : list) {
// 从Future对象上获取任务的返回值,并输出到控制台
System.out.println(">>>" + f.get().toString());


}


Date date2 = new Date();
System.out.println("-----程序运行结束---运行时间="
+ (date2.getTime() - date1.getTime()));
}


}

原创粉丝点击