Promise 模式
簡介
Promise 模式是一種異步編程模式,使用它我們可以先開始一個任務, 並能立即獲取這個任務的執行結果的憑證對象, 而不需要等待任務執行完畢,就可以繼續執行其他操作. 當需要執行結果的時候,可以通過憑證對象,可以調用相應方法來獲取.
這樣操作的好處就是: 避免了不必要的等待, 增強系統的併發性.
成員
- 任務執行器
- 憑證對象
- 自定義任務
- 任務結果對象
實例實現
- 模擬任務 - MyTask
public class MyTask implements Callable<MyPromiseResult> {
private String context;
public MyTask(String context) {
this.context = context;
}
@Override
public MyPromiseResult call() throws Exception {
Random random = new Random();
int workTime = random.nextInt(5 * 1000);
MyPromiseResult result = new MyPromiseResult(workTime, context);
result.setTaskStartTime();
Thread.sleep(workTime);// 模擬工作
result.setTaskEndTime();
return result;
}
}
- 憑證對象使用: FutureTask
- 憑證返回結果: MyPromiseResult
public class MyPromiseResult {
// 任務開始時間
private long taskStartTime;
// 任務結束時間
private long taskEndTime;
// 工作耗時間
private final int workTime;
// 上下文任務名稱
private final String taskName ;
public MyPromiseResult (int workTime, final String taskName) {
this.workTime = workTime;
this.taskName = taskName;
}
public void setTaskStartTime() {
this.taskStartTime = System.currentTimeMillis();
}
public void setTaskEndTime() {
this.taskEndTime = System.currentTimeMillis();
}
public long getTaskStartTime() {
return this.taskStartTime;
}
public long getTaskEndTime() {
return this.taskEndTime;
}
public String getTaskName() {
return taskName;
}
public void print() {
if (taskEndTime > 0) { // 代表完成
System.out.println("完成任務名稱:" + taskName +"...開始時間" + taskStartTime +"...耗時間:"
+ workTime);
}
}
}
- 測試類
public class PromiseTester {
// 任務執行器
static ThreadPoolExecutor threadExecutor = null;
static {
threadExecutor = new ThreadPoolExecutor(2, Runtime.getRuntime().availableProcessors() * 2 ,
60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10),
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
});
}
public static void main(String args[]) throws InterruptedException, ExecutionException {
test();
}
/**
*
* 測試有一個任務它由10個子任務構成, 每個子任務相互獨立
* 只有10個子任務都完成,這個任務纔算完成
* @throws InterruptedException
* @throws ExecutionException
*/
public static void test() throws InterruptedException, ExecutionException {
ConcurrentMap<String, FutureTask<MyPromiseResult>> taskMap = new ConcurrentHashMap<String,
FutureTask<MyPromiseResult>>();
for (int i = 0; i < 10; i ++) {
String name = "task-" + i;
FutureTask<MyPromiseResult> futureTask = PromiseTester.execute(name);
taskMap.put(name, futureTask);
}
FutureTask<MyPromiseResult> task = null;
MyPromiseResult myPromiseResult;
// 輪詢判斷任務是否完成
for (;;) {
if (!taskMap.isEmpty()) {
Iterator<String> iterator = taskMap.keySet().iterator();
while (iterator.hasNext()) {
task = taskMap.get(iterator.next());
if (null != task && task.isDone()) {
myPromiseResult = task.get();
myPromiseResult.print();
taskMap.remove(myPromiseResult.getTaskName());
iterator = taskMap.keySet().iterator();
}
}
} else {
break;
}
Thread.sleep(10);
}
System.out.println("############所有任務完成###############");
}
/**
* 異步提交,並獲取憑證對象
*
* @param context
* @return
*/
public static FutureTask<MyPromiseResult> execute(String context) {
FutureTask<MyPromiseResult> futureTask = new FutureTask<MyPromiseResult>(new MyTask(context));
threadExecutor.execute(futureTask);
return futureTask;
}
}
- 測試結果
完成任務名稱:task-0...開始時間1471786979890...耗時間:352
完成任務名稱:task-1...開始時間1471786979890...耗時間:1526
完成任務名稱:task-3...開始時間1471786981416...耗時間:1835
完成任務名稱:task-2...開始時間1471786980242...耗時間:4534
完成任務名稱:task-4...開始時間1471786983251...耗時間:3672
完成任務名稱:task-5...開始時間1471786984776...耗時間:3908
完成任務名稱:task-6...開始時間1471786986923...耗時間:2037
完成任務名稱:task-7...開始時間1471786988684...耗時間:2948
完成任務名稱:task-9...開始時間1471786991632...耗時間:238
完成任務名稱:task-8...開始時間1471786988960...耗時間:3923
############所有任務完成###############