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

来源:互联网 发布:企业版域名注册通 编辑:程序博客网 时间:2024/05/15 04:42

继续并发专题~

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

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

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

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

[java] view plain copy
print?
  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. }  
package com.zhy.concurrency.futuretask;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;/** * 使用FutureTask来提前加载稍后要用到的数据 *  * @author zhy *  */public class PreLoaderUseFutureTask{    /**     * 创建一个FutureTask用来加载资源     */    private final FutureTask<String> futureTask = new FutureTask<String>(            new Callable<String>()            {                @Override                public String call() throws Exception                {                    Thread.sleep(3000);                    return "加载资源需要3秒";                }            });    public final Thread thread = new Thread(futureTask);    public void start()    {        thread.start();    }    /**     * 获取资源     *      * @return     * @throws ExecutionException      * @throws InterruptedException      */    public String getRes() throws InterruptedException, ExecutionException    {        return futureTask.get();//加载完毕直接返回,否则等待加载完毕    }    public static void main(String[] args) throws InterruptedException, ExecutionException    {        PreLoaderUseFutureTask task = new PreLoaderUseFutureTask();        /**         * 开启预加载资源         */        task.start();        // 用户在真正需要加载资源前进行了其他操作了2秒        Thread.sleep(2000);        /**         * 获取资源         */        System.out.println(System.currentTimeMillis() + ":开始加载资源");        String res = task.getRes();        System.out.println(res);        System.out.println(System.currentTimeMillis() + ":加载资源结束");    }}

运行结果:

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

2、看下Future的API


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

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

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

[java] view plain copy
print?
  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. }  
package com.zhy.concurrency.futuretask;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;/** * 使用FutureTask模拟预加载下一页图书的内容 *  * @author zhy *  */public class BookInstance{    /**     * 当前的页码     */    private volatile int currentPage = 1;    /**     * 异步的任务获取当前页的内容     */    FutureTask<String> futureTask = new FutureTask<String>(            new Callable<String>()            {                @Override                public String call() throws Exception                {                    return loadDataFromNet();                }            });    /**     * 实例化一本书,并传入当前读到的页码     *      * @param currentPage     */    public BookInstance(int currentPage)    {        this.currentPage = currentPage;        /**         * 直接启动线程获取当前页码内容         */        Thread thread = new Thread(futureTask);        thread.start();    }    /**     * 获取当前页的内容     *      * @return     * @throws InterruptedException     * @throws ExecutionException     */    public String getCurrentPageContent() throws InterruptedException,            ExecutionException    {        String con = futureTask.get();        this.currentPage = currentPage + 1;        Thread thread = new Thread(futureTask = new FutureTask<String>(                new Callable<String>()                {                    @Override                    public String call() throws Exception                    {                        return loadDataFromNet();                    }                }));        thread.start();        return con;    }    /**     * 根据页码从网络抓取数据     *      * @return     * @throws InterruptedException     */    private String loadDataFromNet() throws InterruptedException    {        Thread.sleep(1000);        return "Page " + this.currentPage + " : the content ....";    }    public static void main(String[] args) throws InterruptedException,            ExecutionException    {        BookInstance instance = new BookInstance(1);        for (int i = 0; i < 10; i++)        {            long start = System.currentTimeMillis();            String content = instance.getCurrentPageContent();            System.out.println("[1秒阅读时间]read:" + content);            Thread.sleep(1000);            System.out.println(System.currentTimeMillis() - start);        }    }}

输出结果:

[java] view plain copy
print?
  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  
[1秒阅读时间]read:Page 1 : the content ....2001[1秒阅读时间]read:Page 2 : the content ....1000[1秒阅读时间]read:Page 3 : the content ....1001[1秒阅读时间]read:Page 4 : the content ....1000[1秒阅读时间]read:Page 5 : the content ....1001

可以看到,除了第一次观看当前页需要等待网络加载数据的过程(输出的:2001,1000是加载耗时,1000是用户阅读时间),接下来的页面都是瞬间返回(输出的1000是用户阅读时间),完全不需要等待。

代码都是为了讲解FutureTask的应用场景,,,请勿直接在项目中使用。


好了,就到这里,欢迎各位留言。






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

阅读全文
0 0