各種語言在實(shí)現(xiàn)Coroutine方式的支持時,多數(shù)都采用了Actor Model來實(shí)現(xiàn),Actor Model簡單來說就是每個任務(wù)就是一個Actor,Actor之間通過消息傳遞的方式來進(jìn)行交互,而不采用共享的方式,Actor可以看做是一個輕量級的進(jìn)程或線程,通常在一臺4G內(nèi)存的機(jī)器上,創(chuàng)建幾十萬個Actor是毫無問題的。
對于Java應(yīng)用而言,傳統(tǒng)方式下為了支持高并發(fā),由于一個線程只能用于處理一個請求,即使是線程中其實(shí)有很多IO中斷、鎖等待也同樣如此,因此通常的做法是通過啟動很多的線程來支撐高并發(fā),但當(dāng)線程過多時,就造成了CPU需要消耗不少的時間在線程的切換上,從而出現(xiàn)瓶頸,按照上面對Coroutine的描述,Coroutine的方式理論上而言能夠大幅度的提升Java應(yīng)用所能支撐的并發(fā)量。
Kilim是由劍橋的兩位博士開發(fā)的一個用于在Java中使用Coroutine的框架,Kilim基于Java語法,先來看看Kilim中的關(guān)鍵概念。
l Task
可以認(rèn)為Task就是Actor,使用方式和Java Thread基本相同,只是繼承的為Task,覆蓋的為execute方法,啟動也是調(diào)用task的start方法。
l Task的消息發(fā)送機(jī)制
Kilim中通過Mailbox對象來發(fā)送消息,Mailbox的基本原則為可以有多個消息發(fā)送者,但只能有一個消息接收者,發(fā)送的方式有同步發(fā)送、異步發(fā)送和阻塞線程方式的同步發(fā)送三種,同步發(fā)送是指保證一定能將消息放入發(fā)送隊(duì)列中,如當(dāng)前發(fā)送隊(duì)列已滿,則等待到可用為止,阻塞的為當(dāng)前Task;異步發(fā)送則是嘗試將消息放入發(fā)送隊(duì)列一次,如失敗,則返回false,成功則返回true,不會阻塞Task;阻塞線程方式的同步發(fā)送是指阻塞當(dāng)前線程,并保證將消息發(fā)送給接收者,三種方式的使用方法如下:
mailbox.put(messageObject); // 同步發(fā)送
mailbox.putnb(messageObject); // 異步發(fā)送
mailbox.putb(messageObject); // 阻塞線程方式發(fā)送
l Task的消息接收機(jī)制
Kilim中通過Mailbox來接收消息,接收消息的方式有同步接收、異步接收以及阻塞線程方式的同步接收三種,同步接收是指阻塞當(dāng)前Task,直到接收到消息才返回;異步接收是指立刻返回Mailbox中的消息,有就返回,沒有則返回null;阻塞線程方式的同步接收是指阻塞當(dāng)前線程,直到接收到消息才返回,使用方法如下:
mailbox.get(); // 同步接收,傳入long參數(shù)表示等待的超時時間,單位為毫秒
mailbox.getnb(); // 異步接收,立刻返回
mailbox.getb(); // 阻塞線程方式接收
在實(shí)際Java應(yīng)用中使用Coroutine時,通常會出現(xiàn)以下幾種典型的更復(fù)雜的使用場景,由于Actor模式本身就是異步的,因此其天然對異步場景支持的就非常好。
在Kilim中要實(shí)現(xiàn)Task之間的同步調(diào)用非常簡單,代碼如下:
- public class TaskA extends Task{
- public void execute() throws Pausable,Exception{
- Mailbox<Object> result=new Mailbox<Object>();
- Task task=new TaskB(result);
- task.start();
- Object resultObject=result.get();
- System.out.println(resultObject);
- }
- }
- public class TaskB extends Task{
- private Mailbox<Object> result;
- public TaskB(Mailbox<Object> result){
- this.result=result;
- }
- public void execute() throws Pausable,Exception{
- result.put(“result from TaskB”);
- }
- }
Kilim的Mailbox.get并不會阻塞線程,因此這種方式是完全滿足需求的。