Java 并發專題 :FutureTask 實現預加載數據 在線看電子書、瀏覽器瀏覽網頁等

jopen 8年前發布 | 6K 次閱讀 Java開發

繼續并發專題~

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<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() + ":加載資源結束");
    }

}

運行結果:

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

    }
}

輸出結果:

[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

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!