回顾:


接上篇博客

java线程——三种创建线程的方式 ,这篇博客主要介绍第三种方式Callable和Future。比较继承Thread类和实现Runnable接口,接口更加灵活,使用更广泛。但这两种方式都没有返回值,要想返回相应的数据,就要使用Callable和Future方式。 基础:

1、Callable

还是从定义开始,Callable接口有返回值,并且可以抛出异常。

1. 

2.

/**(有返回值的任务,可能抛出异常)


3.

* A task that returns a result and may throw an exception.


4.

* Implementors define a single method with no arguments called


5.

* {@code call}.


6.




7.

* @see Executor


8.

* @since 1.5


9.

* @author Doug Lea


10.

* @param <V> the result type of method {@code call}


11.

*/


12.

@FunctionalInterface


13.


public interface Callable<V> {


14.




15.

V call() throws Exception;


16.

}


17.




2、Future

Future同样也是一个接口,主要方法如下,方法的功能比较容易理解,所以就没有写注释。主要作用:获取任务执行结果,中断任务等。

1. 

2.


package java.util.concurrent;


3.




4.


public interface Future<V> {


5.




6.




7.

boolean cancel(boolean mayInterruptIfRunning);


8.




9.




10.

boolean isCancelled();


11.




12.




13.

boolean isDone();


14.




15.




16.

V get() throws InterruptedException, ExecutionException;


17.




18.




19.

V get(long timeout, TimeUnit unit)



20.

throws InterruptedException, ExecutionException, TimeoutException;


21.

}


22.



3、FutureTask

1. 

2.


public class FutureTask<V> implements RunnableFuture<V> {


3.

......


4.

}


5.




6.


public interface RunnableFuture<V> extends Runnable, Future<V> {


7.

......


8.

}


9.




       FutureTask实现了RunnableFuture接口,而RunnableFuture接口继承了Runnable和Future。也就是说,它既可以作为Runnable被线程执行,也可以作为Future得到Callable返回值。


使用:

方法一:Callable+Future

1. 

2.


public class CallableAndFuture {


3.

/**



4.

* 实现Callable接口


5.

*


6.

* @author YANG


7.

*


8.

*/


9.

public static class MyCallable implements Callable {


10.




11.

private int flag = 0;


12.




13.

public MyCallable(int flag) {


14.




15.

this.flag = flag;


16.




17.

}


18.




19.

// 重写call方法



20.

public String call() throws Exception {


21.

// 情况一:flag=0 返回0



22.

if (this.flag == 0) {


23.




24.

return "flag = 0";


25.




26.

}


27.

// 情况二:flag=1 返回looping 陷入死循环



28.

if (this.flag == 1) {


29.




30.

try {


31.




32.

while (true) {


33.




34.

System.out.println("looping.");


35.




36.

Thread.sleep(2000);


37.




38.

}


39.

// 情况三:出现异常



40.

} catch (InterruptedException e) {


41.




42.

System.out.println("Interrupted");


43.




44.

}


45.




46.

return "false";


47.




48.

} else {


49.




50.

throw new Exception("Bad flag value!");


51.




52.

}


53.




54.

}


55.




56.

}


57.




58.

public static void main(String[] args) {


59.




60.

// 定义3个Callable类型的任务,构造方法中制定flag的值



61.

MyCallable task1 = new MyCallable(0);


62.




63.

MyCallable task2 = new MyCallable(1);


64.




65.

MyCallable task3 = new MyCallable(2);


66.




67.

// 创建一个执行任务的服务



68.




69.

ExecutorService es = Executors.newFixedThreadPool(3);


70.




71.

try {


72.




73.

// 提交并执行任务,任务启动时返回了一个Future对象,



74.




75.

// 如果想得到任务执行的结果或者是异常可对这个Future对象进行操作



76.




77.

Future future1 = null;


78.




79.

future1 = es.submit(task1);


80.




81.

// 获得第一个任务的结果,如果调用get方法,当前线程会等待任务执行完毕后才往下执行



82.




83.

System.out.println("task1: " + future1.get());


84.




85.

Future future2 = es.submit(task2);


86.




87.

// 等待5秒后,再停止第二个任务。因为第二个任务进行的是无限循环



88.




89.

Thread.sleep(5000);


90.




91.

System.out.println("task2 cancel: " + future2.cancel(true));


92.




93.

// 测试抛出异常



94.




95.

Future future3 = es.submit(task3);


96.




97.

System.out.println("task3: " + future3.get());


98.




99.

} catch (Exception e) {


100.




101.

System.out.println(e.toString());


102.




103.

}


104.




105.

// 停止任务执行服务



106.




107.

es.shutdownNow();


108.




109.

}


110.

}


111.




执行结果:

java线程——详解Callable、Future和FutureTask_高并发



方法二:Callable+FutureTask

      分析两种方法不同之处就在于Future和FutureTask,其中一个是接口,一个是类。因此,只有main方法调用部分不同,上面的MyCallable类中的内容保持不变。

1. 

2.


public static void main(String[] args) {


3.




4.

MyCallable task1 = new MyCallable(0);


5.

FutureTask ft1 = new FutureTask(task1);


6.

MyCallable task2 = new MyCallable(1);


7.

FutureTask ft2 = new FutureTask(task2);


8.

MyCallable task3 = new MyCallable(2);


9.

FutureTask ft3 = new FutureTask(task3);


10.




11.

try {


12.

//启动task1



13.

new Thread(ft1, "子线程").start();


14.

System.out.println(ft1.get());


15.




16.




17.

//等待5秒后,停止task2



18.

new Thread(ft2, "子线程").start();


19.

Thread.sleep(5000);


20.

System.out.println("task2 cancel:" + ft2.cancel(true));


21.




22.

//启动task3



23.

new Thread(ft3, "子线程").start();


24.

System.out.println("task3:" + ft3.get());


25.

} catch (InterruptedException | ExecutionException e) {


26.




27.

System.out.println(e.toString());


28.

}


29.




30.

}


31.



       

       其执行结果与方法一完全相同,对比这两种方式,第二种比较容易读懂,第一种相对困难些。下篇博客我们介绍Executor、ExecutorService等内容,相信之后理解起来就会很轻松了。