Java 并发专题 :FutureTask 实现预加载数据 在线看电子书、浏览器浏览网页等

简介: 转自:http://blog.csdn.net/lmj623565791/article/details/26817403  继续并发专题~ FutureTask 有点类似Runnable,都可以通过Thread来启动,不过FutureTask可以返回执行完毕的数据,并且FutureTask的get方法支持阻塞。 由于:FutureTask可以返回执行完毕的数据,

转自:http://blog.csdn.net/lmj623565791/article/details/26817403 


继续并发专题~

FutureTask 有点类似Runnable,都可以通过Thread来启动,不过FutureTask可以返回执行完毕的数据,并且FutureTask的get方法支持阻塞。

由于:FutureTask可以返回执行完毕的数据,并且FutureTask的get方法支持阻塞这两个特性,我们可以用来预先加载一些可能用到资源,然后要用的时候,调用get方法获取(如果资源加载完,直接返回;否则继续等待其加载完成)。

下面通过两个例子来介绍下:

1、使用FutureTask来预加载稍后要用的的数据。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  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.                     Thread.sleep(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.         PreLoaderUseFutureTask task = new PreLoaderUseFutureTask();  
  53.         /** 
  54.          * 开启预加载资源 
  55.          */  
  56.         task.start();  
  57.         // 用户在真正需要加载资源前进行了其他操作了2秒  
  58.         Thread.sleep(2000);  
  59.   
  60.         /** 
  61.          * 获取资源 
  62.          */  
  63.         System.out.println(System.currentTimeMillis() + ":开始加载资源");  
  64.         String res = task.getRes();  
  65.         System.out.println(res);  
  66.         System.out.println(System.currentTimeMillis() + ":加载资源结束");  
  67.     }  
  68.   
  69. }  

运行结果:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. 1400902789275:开始加载资源  
  2. 加载资源需要3秒  
  3. 1400902790275:加载资源结束  
可以看到,本来加载资源的时间需要3秒,现在只花费了1秒,如果用户其他操作时间更长,则可直接返回,极大增加了用户体验。

2、看下Future的API


可以看到Future的API,还是比简单的,见名知意的感觉,get( long , TimeUnit )还能支持,设置最大等待时间,比如某个操作耗时太长,就可以取消了。

3、FutureTask模拟,用户在线观看电子书的预加载功能

用户观看当前页时,后台预先把下一页加载好,这样可以大幅度提高用户的体验,不需要每一页都等待加载,用户会觉得此电子书软件很流畅,哈哈,用户觉得好,才是真的好。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  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.     FutureTask<String> futureTask = 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.         Thread thread = 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.         Thread thread = 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.         Thread.sleep(1000);  
  84.         return "Page " + this.currentPage + " : the content ....";  
  85.   
  86.     }  
  87.   
  88.     public static void main(String[] args) throws InterruptedException,  
  89.             ExecutionException  
  90.     {  
  91.         BookInstance instance = new BookInstance(1);  
  92.         for (int i = 0; i < 10; i++)  
  93.         {  
  94.             long start = System.currentTimeMillis();  
  95.             String content = instance.getCurrentPageContent();  
  96.             System.out.println("[1秒阅读时间]read:" + content);  
  97.             Thread.sleep(1000);  
  98.             System.out.println(System.currentTimeMillis() - start);  
  99.         }  
  100.   
  101.     }  
  102. }  

输出结果:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  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是用户阅读时间),完全不需要等待。


目录
相关文章
|
20天前
|
前端开发 JavaScript Java
java常用数据判空、比较和类型转换
本文介绍了Java开发中常见的数据处理技巧,包括数据判空、数据比较和类型转换。详细讲解了字符串、Integer、对象、List、Map、Set及数组的判空方法,推荐使用工具类如StringUtils、Objects等。同时,讨论了基本数据类型与引用数据类型的比较方法,以及自动类型转换和强制类型转换的规则。最后,提供了数值类型与字符串互相转换的具体示例。
|
27天前
|
JSON Java 程序员
Java|如何用一个统一结构接收成员名称不固定的数据
本文介绍了一种 Java 中如何用一个统一结构接收成员名称不固定的数据的方法。
26 3
|
1月前
|
Java 程序员 容器
Java中的变量和常量:数据的‘小盒子’和‘铁盒子’有啥不一样?
在Java中,变量是一个可以随时改变的数据容器,类似于一个可以反复打开的小盒子。定义变量时需指定数据类型和名称。例如:`int age = 25;` 表示定义一个整数类型的变量 `age`,初始值为25。 常量则是不可改变的数据容器,类似于一个锁死的铁盒子,定义时使用 `final` 关键字。例如:`final int MAX_SPEED = 120;` 表示定义一个名为 `MAX_SPEED` 的常量,值为120,且不能修改。 变量和常量的主要区别在于变量的数据可以随时修改,而常量的数据一旦确定就不能改变。常量主要用于防止意外修改、提高代码可读性和便于维护。
|
1月前
|
存储 缓存 安全
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见
在 Java 编程中,创建临时文件用于存储临时数据或进行临时操作非常常见。本文介绍了使用 `File.createTempFile` 方法和自定义创建临时文件的两种方式,详细探讨了它们的使用场景和注意事项,包括数据缓存、文件上传下载和日志记录等。强调了清理临时文件、确保文件名唯一性和合理设置文件权限的重要性。
93 2
|
1月前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
33 2
|
1月前
|
存储 分布式计算 Java
存算分离与计算向数据移动:深度解析与Java实现
【11月更文挑战第10天】随着大数据时代的到来,数据量的激增给传统的数据处理架构带来了巨大的挑战。传统的“存算一体”架构,即计算资源与存储资源紧密耦合,在处理海量数据时逐渐显露出其局限性。为了应对这些挑战,存算分离(Disaggregated Storage and Compute Architecture)和计算向数据移动(Compute Moves to Data)两种架构应运而生,成为大数据处理领域的热门技术。
64 2
|
1月前
|
SQL Java OLAP
java实现“数据平滑升级”
java实现“数据平滑升级”
44 2
|
2月前
|
SQL Java 关系型数据库
java连接mysql查询数据(基础版,无框架)
【10月更文挑战第12天】该示例展示了如何使用Java通过JDBC连接MySQL数据库并查询数据。首先在项目中引入`mysql-connector-java`依赖,然后通过`JdbcUtil`类中的`main`方法实现数据库连接、执行SQL查询及结果处理,最后关闭相关资源。
182 6
|
1月前
|
SQL Java OLAP
java实现“数据平滑升级”
java实现“数据平滑升级”
21 0
|
2月前
|
NoSQL 前端开发 MongoDB
前端的全栈之路Meteor篇(三):运行在浏览器端的NoSQL数据库副本-MiniMongo介绍及其前后端数据实时同步示例
MiniMongo 是 Meteor 框架中的客户端数据库组件,模拟了 MongoDB 的核心功能,允许前端开发者使用类似 MongoDB 的 API 进行数据操作。通过 Meteor 的数据同步机制,MiniMongo 与服务器端的 MongoDB 实现实时数据同步,确保数据一致性,支持发布/订阅模型和响应式数据源,适用于实时聊天、项目管理和协作工具等应用场景。