继续并发专题~

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

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

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

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

package com.zhy.concurrency.futuretask;

import <a href="http://lib.csdn.net/base/17" class="replace_word" title="Java EE知识库" target="_blank" style="color:#df3434; font-weight:bold;">java</a>.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();
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(); /**
* 获取资源
*/
System.out.println(System.currentTimeMillis() + ":开始加载资源");
String res = task.getRes();
System.out.println(res);
System.out.println(System.currentTimeMillis() + ":加载资源结束");
} }

运行结果:

:开始加载资源
加载资源需要3秒
:加载资源结束

可以看到,本来加载资源的时间需要3秒,现在只花费了1秒,如果用户其他操作时间更长,则可直接返回,极大增加了用户体验。

2、看下Future的API

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

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

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

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 = ; /**
* 异步的任务获取当前页的内容
*/
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 + ;
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();
return "Page " + this.currentPage + " : the content ...."; } public static void main(String[] args) throws InterruptedException,
ExecutionException
{
BookInstance instance = new BookInstance();
for (int i = ; i < ; i++)
{
long start = System.currentTimeMillis();
String content = instance.getCurrentPageContent();
System.out.println("[1秒阅读时间]read:" + content);
Thread.sleep();
System.out.println(System.currentTimeMillis() - start);
} }
}
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 = ; /**
* 异步的任务获取当前页的内容
*/
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 + ;
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();
return "Page " + this.currentPage + " : the content ...."; } public static void main(String[] args) throws InterruptedException,
ExecutionException
{
BookInstance instance = new BookInstance();
for (int i = ; i < ; i++)
{
long start = System.currentTimeMillis();
String content = instance.getCurrentPageContent();
System.out.println("[1秒阅读时间]read:" + content);
Thread.sleep();
System.out.println(System.currentTimeMillis() - start);
} }
}

输出结果:

[1秒阅读时间]read:Page  : the content ....

[1秒阅读时间]read:Page  : the content ....

[1秒阅读时间]read:Page  : the content ....

[1秒阅读时间]read:Page  : the content ....

[1秒阅读时间]read:Page  : the content ....

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

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

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

Java 并发专题 :FutureTask 实现预加载数据 在线看电子书、浏览器浏览网页等的更多相关文章

  1. 基于spring的web项目启动时预加载数据到ServletContext

    1.要在web启动时预加载数据到ServletContext,实现方法有很多,一种比较简单的方案就是: 1)新建一个bean,定义其初始化方法: <bean id="beanId&qu ...

  2. 巧力避免ViewPager的预加载数据,Tablayout+Fragment+viewPager

    问题描述 最近在进行一个项目的开发,其中使用到了Tablayout+Fragment+viewPager来搭建一个基本的框架,从而出现了设置数据适配器的时候,item的位置错乱问题.我打印log日志的 ...

  3. CommandLineRunner预加载数据

    在使用SpringBoot构建项目时,我们通常有一些预先数据的加载.那么SpringBoot提供了一个简单的方式来实现–CommandLineRunner. CommandLineRunner是一个接 ...

  4. java攻城狮之路(Android篇)--widget_webview_metadata_popupwindow_tabhost_分页加载数据_菜单

    一.widget:桌面小控件1 写一个类extends AppWidgetProvider 2 在清单文件件中注册: <receiver android:name=".ExampleA ...

  5. js中的预加载与懒加载(延迟加载)

    js中加载分两种:预加载与延迟加载 一.  预加载,增强用户的体验,但会加载服务器的负担.一般会使用多种 CSS(background).JS(Image).HTML(<img />) . ...

  6. MailOtto 实现完美预加载以及源码解读

    背景: 最近项目组需要一个小课题分享,小白刚好从微博里看到一个这样有趣的开源工具MailOtto,是阿里巴巴员工 Drakeet 维护的一个专注懒事件的事件总线,gitHub地址为:https://g ...

  7. web前端图片预加载

    是什么? 浏览器会缓存静态资源(hmtl/css/img等).图片预加载就是让浏览器提前缓存图片,提升用户体验. 浏览器什么情况下会下载图片? 1,解析到html中img的src属性的时候 2,解析到 ...

  8. html预加载之link标签

    我们之前提及过link rel 里面有preload和prefetch.modulepreload,都是用于预加载资源 <link rel="preload" href=&q ...

  9. Gorm 预加载及输出处理(二)- 查询输出处理

    上一篇<Gorm 预加载及输出处理(一)- 预加载应用>中留下的三个问题: 如何自定义输出结构,只输出指定字段? 如何自定义字段名,并去掉空值字段? 如何自定义时间格式? 这一篇先解决前两 ...

随机推荐

  1. Android 中常用代码片段

    一:AsyncTask 的使用 (1)activity_main.xml <TextView android:id="@+id/tvInfo" android:layout_ ...

  2. Eclipse调试Bug的七种常用技巧(转)

        注意事项及小结: (1)Line Breakpoint:如果设置Conditional,监控的变量需要比当前行高一级block,譬如for(int i=0;i<20;i++)中的i,fo ...

  3. win7 奇怪的temp用户

    在C:\Users\TEMP 有个temp用户,win+r打开的也是 C:\Users\TEMP>,而不是C:\User\Administrator. 以下文章转自: http://hi.bai ...

  4. kibana 版本kibana-4.3.1 修改地图

    进入到安装目录下的src/ui/public/vislib/visualizations/目录 1.编辑_map.js文件 1 2 //url: 'https://otile{s}-s.mqcdn.c ...

  5. UESTC_邱老师降临小行星 2015 UESTC Training for Search Algorithm & String<Problem B>

    B - 邱老师降临小行星 Time Limit: 10000/5000MS (Java/Others)     Memory Limit: 65536/65535KB (Java/Others) Su ...

  6. UVA_埃及分数(Hard Version) UVA 12588

    Problem EEg[y]ptian Fractions (HARD version)Given a fraction a/b, write it as a sum of different Egy ...

  7. LeeCode-Remove Linked List Elements

    Remove all elements from a linked list of integers that have value val. ExampleGiven: 1 --> 2 --& ...

  8. UVA 1599 Ideal Path(bfs1+bfs2,双向bfs)

    给一个n个点m条边(<=n<=,<=m<=)的无向图,每条边上都涂有一种颜色.求从结点1到结点n的一条路径,使得经过的边数尽量少,在此前提下,经过边的颜色序列的字典序最小.一对 ...

  9. Unity编辑器扩展Texture显示选择框

    学习NGUI插件的时候,突然间有一个问题为什么它这些属性可以通过弹出窗口来选中呢? 而我自己写的组件只能使用手动拖放的方式=.=. Unity开发了组件Inspector视图扩展API,如果我们要写插 ...

  10. 树的直径 poj 2631

    树的直径:从随意一点出发,BFS找到最远的距离,然后在从该点出发BFS找到最远的距离 #include <iostream> #include <algorithm> #inc ...