1. 程式人生 > >Guava併發(3)——實現的非同步回撥

Guava併發(3)——實現的非同步回撥

一、說明:

1、裝飾Concurrent包裡的ExecutorService

ListeningExecutorService guavaExecutor = MoreExecutors
				.listeningDecorator(Executors.newSingleThreadExecutor());
2、ListenableFuture的建立
final ListenableFuture<T> listenableFuture = guavaExecutor
				.submit(new Callable<T>() {
			。。。。。。
				});
3、ListenableFuture註冊監聽器,即非同步呼叫完成時會在指定的執行緒池中執行註冊的監聽器
listenableFuture.addListener(new Runnable() {
			。。。。。。
		}, Executors.newSingleThreadExecutor());

4、Futures方法進行Callback
Futures.addCallback(listenableFuture2, new FutureCallback<T>() {
					@Override
					public void onSuccess(Tresult) {
						。。。。。。
					}
					@Override
					public void onFailure(Throwable t) {
					}
				}
		);

二、程式碼:

package com.wll.guava.concurrent;

import com.google.common.util.concurrent.*;
import java.util.concurrent.*;

/**
 * 使用guava實現非同步回撥 {@link java.util.concurrent.Future}
 * {@link com.google.common.util.concurrent.ListenableFuture}
 * {@link com.google.common.util.concurrent.FutureCallback}
 *
 * @author landon
 */
public class FutureCallbackExample {

	public static void main(String[] args) throws Exception {
		nativeFuture();
		Thread.sleep(3000L);

		guavaFuture();
		Thread.sleep(3000L);

		guavaFuture2();
	}


	public static void nativeFuture() throws Exception {
		// 原生的Future模式,實現非同步
		ExecutorService nativeExecutor = Executors.newSingleThreadExecutor();
		Future<String> nativeFuture = nativeExecutor
				.submit(new Callable<String>() {
					@Override
					public String call() throws Exception {
						// 使用sleep模擬呼叫耗時
						TimeUnit.SECONDS.sleep(1);
						return  "[" + Thread.currentThread().getName() +"]: 併發包Future返回結果" ;
					}
				});
		// Future只實現了非同步,而沒有實現回撥.所以此時主執行緒get結果時阻塞.或者可以輪訓以便獲取非同步呼叫是否完成
		System.out.println("[" + Thread.currentThread().getName() +"]====>"+ nativeFuture.get());

	}
	public static void guavaFuture() throws Exception {
		System.out.println("-------------------------------- 神祕的分割線 -----------------------------------");
		// 好的實現應該是提供回撥,即非同步呼叫完成後,可以直接回調.本例採用guava提供的非同步回撥介面,方便很多.
		ListeningExecutorService guavaExecutor = MoreExecutors
				.listeningDecorator(Executors.newSingleThreadExecutor());
		final ListenableFuture<String> listenableFuture = guavaExecutor
				.submit(new Callable<String>() {

					@Override
					public String call() throws Exception {
						TimeUnit.SECONDS.sleep(1);
						return  "[" + Thread.currentThread().getName() +"]: guava的Future返回結果";
					}
				});

		// 註冊監聽器,即非同步呼叫完成時會在指定的執行緒池中執行註冊的監聽器
		listenableFuture.<span style="color:#FF0000;">addListener</span>(new Runnable() {
			@Override
			public void run() {
				try {
					String logTxt = "[" + Thread.currentThread().getName() +"]: guava對返回結果進行非同步CallBack(Runnable):"
							+ listenableFuture.get();
					System.out.println(logTxt);
				} catch (Exception e) {
				}
			}
		}, Executors.newSingleThreadExecutor());

		// 主執行緒可以繼續執行,非同步完成後會執行註冊的監聽器任務.
		System.out.println( "[" + Thread.currentThread().getName() +"]: guavaFuture1執行結束");
	}

	public static void guavaFuture2() throws Exception {
		System.out.println("-------------------------------- 神祕的分割線 -----------------------------------");
		// 除了ListenableFuture,guava還提供了FutureCallback介面,相對來說更加方便一些.
		ListeningExecutorService guavaExecutor2 = MoreExecutors
				.listeningDecorator(Executors.newSingleThreadExecutor());
		final ListenableFuture<String> listenableFuture2 = guavaExecutor2
				.submit(new Callable<String>() {
					@Override
					public String call() throws Exception {
						TimeUnit.SECONDS.sleep(1);
						String logText = "[" + Thread.currentThread().getName() +"]: guava的Future返回結果";
						System.out.println(logText);
						return logText;
					}
				});

		// 注意這裡沒用指定執行回撥的執行緒池,從輸出可以看出,<span style="color:#FF0000;">預設是和執行非同步操作的執行緒是同一個.</span>
		Futures.addCallback(listenableFuture2, new FutureCallback<String>() {
					@Override
					public void onSuccess(String result) {
						String logTxt = "[" + Thread.currentThread().getName() +"]=======>對回撥結果【"+result+"】進行FutureCallback,經測試,發現是和回撥結果處理執行緒為同一個執行緒";
						System.out.println(logTxt);
					}
					@Override
					public void onFailure(Throwable t) {
					}
				}
		);
		// 主執行緒可以繼續執行,非同步完成後會執行註冊的監聽器任務.
		System.out.println( "[" + Thread.currentThread().getName() +"]: guavaFuture2執行結束");
	}
}

三、執行結果

D:\DevPro\Java\jdk1.7.0_79\bin\java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:62193,suspend=y,server=n -Dfile.encoding=UTF-8 -classpath "D:\DevPro\Java\jdk1.7.0_79\jre\lib\jce.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\jfr.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\management-agent.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\resources.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\charsets.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\javaws.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\deploy.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\plugin.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\jsse.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\rt.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\jfxrt.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\ext\access-bridge-64.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\ext\dnsns.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\ext\jaccess.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\ext\sunec.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\ext\sunjce_provider.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\ext\sunmscapi.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\ext\zipfs.jar;D:\DevPro\Java\jdk1.7.0_79\jre\lib\ext\localedata.jar;E:\DevCode\guavaLearn\target\classes;C:\Users\Administrator\.m2\repository\com\google\guava\guava\18.0\guava-18.0.jar;C:\Users\Administrator\.m2\repository\org\mockito\mockito-all\2.0.2-beta\mockito-all-2.0.2-beta.jar;C:\Users\Administrator\.m2\repository\junit\junit\4.12\junit-4.12.jar;C:\Users\Administrator\.m2\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;C:\Users\Administrator\.m2\repository\com\alibaba\fastjson\1.2.7\fastjson-1.2.7.jar;D:\DevPro\JetBrains\IntelliJ IDEA 14.0.2\lib\idea_rt.jar" com.wll.guava.concurrent.FutureCallbackExample
Connected to the target VM, address: '127.0.0.1:62193', transport: 'socket'
[main]====>[pool-1-thread-1]: 併發包Future返回結果
-------------------------------- 神祕的分割線 -----------------------------------
[main]: guavaFuture1執行結束
[pool-3-thread-1]: guava對返回結果進行非同步CallBack(Runnable):[pool-2-thread-1]: guava的Future返回結果
-------------------------------- 神祕的分割線 -----------------------------------
[main]: guavaFuture2執行結束
[pool-4-thread-1]: guava的Future返回結果
[pool-4-thread-1]=======>對回撥結果【[pool-4-thread-1]: guava的Future返回結果】進行FutureCallback,經測試,發現是和回撥結果處理執行緒為同一個執行緒
Disconnected from the target VM, address: '127.0.0.1:62193', transport: 'socket'

Process finished with exit code -1

四、總結:

略。