異步編程分爲兩種:JVM內部的異步編程和JVM之間的異步編程。本文主要思考JVM內部的異步(簡稱爲異步任務)。JVM之間的異步可以通過MQ等方式實現。
1、異步任務是什麼?
異步任務是由一系列的事件處理器(EventHandler)和Event(事件)組成,EventHandlers之間的通訊通過Event來實現。每一個EventHandler佔用一個線程(Thread)。
2、異步任務需要提供哪些功能
A、任務恢復機制:在任務被異常中斷的情況下,可以恢復任務。
B、日誌追蹤機制:通過日誌信息,來判斷任務的執行情況,並對失敗的任務進行定位。
C、元素鎖定機制:異步任務所涉及到的各種元素,有的需要鎖定,防止意外的操作,影響任務得進行。
3、異步任務的粒度?
粒度一:Event對應EventHandler。EventHandler響應傳過來的Event,但不改變Event的狀態
粒度二:Event對應異步任務。Event在異步任務內部進行傳遞,內部的EventHandler可以更變Event的狀態,並傳遞到下一個節點。
4、異步任務如何切分?
異步任務有多個EventHandler組成,設計一個EventHandler的關鍵要素是快、全、少。
A、快的含義是減少IO操作,爭取所有操作都在內存中完成。IO操作越多,處理時間越長,EventHandler越不穩定,任務完成得越慢。
B、全的含義是每一個handler所處理的事情都是完整有意義的,不可分割的。用數據庫的話來說就是一個完整的事務。
C、少的含義是一次完成一件事情。
5、異步任務可以解決那些問題?
異步任務可以解決【輪詢線程】的問題。過於複雜的輪詢線程是脆弱的,因爲有太多不可靠因素會導致線程死亡,就算線程的最外層加上try...catch,也僅僅是指標不治本。
異步任務可以降低模塊之間的耦合。由於Handler之間是通過Event來觸發的,耦合程度降至爲【數據耦合】。
6、異步任務需要依賴什麼?
異步任務核心之一是事件派發器,派發器本質上是一個生產者消費者隊列,生產者負責發佈事件,消費者負責派發事件到處理器中。選擇的高性能隊列是核心任務,JDK自帶的Queue並不能滿足要求,可以選擇Disruptor框架。
7、三種角色:
A.event object(Event):就是事件產生時具體的“事件”,用於listener的相應的方法之中,作爲參數,一般存在與listerner的方法之中
B.event source:具體的接受事件的實體,比如說,你點擊一個button,那麼button就是event source,這樣你必須使button對某些事件進行相應,你就需要註冊特定的listener。
C.event listener(EventHandler):具體的對監聽的事件類,當有其對應的event object產生的時候,它就調用相應的方法,進行處理。
下面來看個實例,其組織結構圖如下:
Source.java源碼如下:
package com.event.test01;
import java.util.*;
public class Source {
private Vector<ListenerDao> repository = new Vector<ListenerDao>();
ListenerDao dl;
public Source() {
}
public void addListener(ListenerDao dl) {
repository.addElement(dl);
}
public void notifyEvent() {
Enumeration<ListenerDao> enumx = repository.elements();
while (enumx.hasMoreElements()) {
dl = (ListenerDao) enumx.nextElement();
dl.demoEvent(new Event(this)); // 通知所有監聽此事件的監聽者
}
}
}
Event.java源碼如下:package com.event.test01;
import java.util.EventObject;
public class Event extends EventObject {
Object obj;
public Event(Object source) {
super(source);
obj = source;
}
public Object getSource() {// 獲得事件源的引用
return obj;
}
}
ListenerDao源碼如下:package com.event.test01;
import java.util.EventListener;
public interface ListenerDao extends EventListener {
public void demoEvent(Event dm);
}
如下源碼是ListenerDao的實現類:package com.event.test01;
public class ListenerDaoImpl01 implements ListenerDao {
public void demoEvent(Event de) {
System.out.println("Inside listener1...");
}
}
package com.event.test01;
public class ListenerDaoImpl02 implements ListenerDao {
public void demoEvent(Event de) {
System.out.println("Inside listener2...");
}
}
最後編寫測試實例,如下:package com.event.test01;
public class TestDemo {
public TestDemo() {
try {
Source ds = new Source(); //事件源
ListenerDaoImpl01 l1 = new ListenerDaoImpl01();
ListenerDaoImpl02 l2 = new ListenerDaoImpl02();
ds.addListener(l1);
ds.addListener(l2);
ds.addListener(new ListenerDao() {
public void demoEvent(Event event) {
System.out.println("Method come from 匿名類...");
}
});
ds.notifyEvent(); // 事件源產生事件
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void main(String args[]) {
new TestDemo();
}
}
運行的結果如下:
Inside listener1...
Inside listener2...
Method come from 匿名類...