抓取网页生成电子书(继续并发专题~FutureTask有点类似Runnable的get方法支持阻塞)

优采云 发布时间: 2022-01-06 23:11

  抓取网页生成电子书(继续并发专题~FutureTask有点类似Runnable的get方法支持阻塞)

  继续并发话题~

  FutureTask有点类似于Runnable,可以由Thread启动,但是FutureTask执行后可以返回数据,FutureTask的get方法支持阻塞。

  因为:FutureTask可以返回已经执行过的数据,而FutureTask的get方法支持阻塞这两个特性,我们可以用它来预加载一些可能会用到的资源,然后调用get方法来获取想使用它(如果资源已加载,则直接返回;否则,继续等待其加载完成)。

  下面举两个例子来介绍:

  1、使用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 PreLoaderUseFutureTask

{

/**

* 创建一个FutureTask用来加载资源

*/

private final FutureTask futureTask = new FutureTask(

new Callable()

{

@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() + ":加载资源结束");

}

}

  操作结果:

  1400902789275:开始加载资源

加载资源需要3秒

1400902790275:加载资源结束

  可以看到,原来加载资源需要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 = 1;

/**

* 异步的任务获取当前页的内容

*/

FutureTask futureTask = new FutureTask(

new Callable()

{

@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(

new Callable()

{

@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);

}

}

}

  输出结果:

  [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的应用场景,请勿直接在项目中使用。

  好了,就这样了,欢迎大家留言。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线