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

优采云 发布时间: 2022-03-25 03:17

  抓取网页生成电子书(继续并发专题~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人工客服


线