FutureTask 有点类似Runnable,都可以通过Thread来启动,不过FutureTask可以返回执行完毕的数据,并且FutureTask的get方法支持阻塞。
由于:FutureTask可以返回执行完毕的数据,并且FutureTask的get方法支持阻塞这两个特性,我们可以用来预先加载一些可能用到资源,然后要用的时候,调用get方法获取(如果资源加载完,直接返回;否则继续等待其加载完成)。
下面通过两个例子来介绍下:
1、使用FutureTask来预加载稍后要用的的数据。
[java] view plain copy
1. package com.zhy.concurrency.futuretask;
2.
3. import java.util.concurrent.Callable;
4. import java.util.concurrent.ExecutionException;
5. import java.util.concurrent.FutureTask;
6.
7. /**
8. * 使用FutureTask来提前加载稍后要用到的数据
9. *
10. * @author zhy
11. *
12. */
13. public class PreLoaderUseFutureTask
14. {
15. /**
16. * 创建一个FutureTask用来加载资源
17. */
18. private final FutureTask<String> futureTask = new FutureTask<String>(
19. new Callable<String>()
20. {
21. @Override
22. public String call() throws Exception
23. {
24. 3000);
25. return "加载资源需要3秒";
26. }
27. });
28.
29. public final Thread thread = new Thread(futureTask);
30.
31. public void start()
32. {
33. thread.start();
34. }
35.
36. /**
37. * 获取资源
38. *
39. * @return
40. * @throws ExecutionException
41. * @throws InterruptedException
42. */
43. public String getRes() throws InterruptedException, ExecutionException
44. {
45. return futureTask.get();//加载完毕直接返回,否则等待加载完毕
46.
47. }
48.
49. public static void main(String[] args) throws InterruptedException, ExecutionException
50. {
51.
52. new PreLoaderUseFutureTask();
53. /**
54. * 开启预加载资源
55. */
56. task.start();
57. // 用户在真正需要加载资源前进行了其他操作了2秒
58. 2000);
59.
60. /**
61. * 获取资源
62. */
63. ":开始加载资源");
64. String res = task.getRes();
65. System.out.println(res);
66. ":加载资源结束");
67. }
68.
69. }
运行结果:
[java] view plain copy
1. 1400902789275:开始加载资源
2. 加载资源需要3秒
3. 1400902790275:加载资源结束
可以看到,本来加载资源的时间需要3秒,现在只花费了1秒,如果用户其他操作时间更长,则可直接返回,极大增加了用户体验。
2、看下Future的API
可以看到Future的API,还是比简单的,见名知意的感觉,get( long , TimeUnit )还能支持,设置最大等待时间,比如某个操作耗时太长,就可以取消了。
3、FutureTask模拟,用户在线观看电子书的预加载功能
用户观看当前页时,后台预先把下一页加载好,这样可以大幅度提高用户的体验,不需要每一页都等待加载,用户会觉得此电子书软件很流畅,哈哈,用户觉得好,才是真的好。
[java] view plain copy
1. package com.zhy.concurrency.futuretask;
2.
3. import java.util.concurrent.Callable;
4. import java.util.concurrent.ExecutionException;
5. import java.util.concurrent.FutureTask;
6.
7.
8. /**
9. * 使用FutureTask模拟预加载下一页图书的内容
10. *
11. * @author zhy
12. *
13. */
14. public class BookInstance
15. {
16.
17. /**
18. * 当前的页码
19. */
20. private volatile int currentPage = 1;
21.
22. /**
23. * 异步的任务获取当前页的内容
24. */
25. new FutureTask<String>(
26. new Callable<String>()
27. {
28. @Override
29. public String call() throws Exception
30. {
31. return loadDataFromNet();
32. }
33. });
34.
35. /**
36. * 实例化一本书,并传入当前读到的页码
37. *
38. * @param currentPage
39. */
40. public BookInstance(int currentPage)
41. {
42. this.currentPage = currentPage;
43. /**
44. * 直接启动线程获取当前页码内容
45. */
46. new Thread(futureTask);
47. thread.start();
48. }
49.
50. /**
51. * 获取当前页的内容
52. *
53. * @return
54. * @throws InterruptedException
55. * @throws ExecutionException
56. */
57. public String getCurrentPageContent() throws InterruptedException,
58. ExecutionException
59. {
60. String con = futureTask.get();
61. this.currentPage = currentPage + 1;
62. new Thread(futureTask = new FutureTask<String>(
63. new Callable<String>()
64. {
65. @Override
66. public String call() throws Exception
67. {
68. return loadDataFromNet();
69. }
70. }));
71. thread.start();
72. return con;
73. }
74.
75. /**
76. * 根据页码从网络抓取数据
77. *
78. * @return
79. * @throws InterruptedException
80. */
81. private String loadDataFromNet() throws InterruptedException
82. {
83. 1000);
84. return "Page " + this.currentPage + " : the content ....";
85.
86. }
87.
88. public static void main(String[] args) throws InterruptedException,
89. ExecutionException
90. {
91. new BookInstance(1);
92. for (int i = 0; i < 10; i++)
93. {
94. long start = System.currentTimeMillis();
95. String content = instance.getCurrentPageContent();
96. "[1秒阅读时间]read:" + content);
97. 1000);
98. System.out.println(System.currentTimeMillis() - start);
99. }
100.
101. }
102. }
输出结果:
[java] view plain copy
1. [1秒阅读时间]read:Page 1 : the content ....
2. 2001
3. [1秒阅读时间]read:Page 2 : the content ....
4. 1000
5. [1秒阅读时间]read:Page 3 : the content ....
6. 1001
7. [1秒阅读时间]read:Page 4 : the content ....
8. 1000
9. [1秒阅读时间]read:Page 5 : the content ....
10. 1001
可以看到,除了第一次观看当前页需要等待网络加载数据的过程(输出的:2001,1000是加载耗时,1000是用户阅读时间),接下来的页面都是瞬间返回(输出的1000是用户阅读时间),完全不需要等待。
代码都是为了讲解FutureTask的应用场景,,,请勿直接在项目中使用。