java多線程

java多線程包括建立線程,啓動線程,控制線程,以及線程同步,以及利用java內建支持的線程池來提升多線程性能。java

進程具備數據庫

獨立性:是系統中獨立存在的實體,擁有本身獨立的資源,有本身的私有地址空間。編程

動態性:程序一旦進入內存,就變成一個進程,所以進程是系統中活動的指令集合,加入了時間的概念,進程有本身的生命週期和各類不一樣的狀態。這在程序中是不具有的。數組

併發性:多個進程能夠在單個處理器上併發執行,不會互相影響。緩存

併發和並行的區別:並行是指同一時刻,剁掉指令在多個處理器上同時執行。併發是指同一時刻只有一條指令執行,但過個進程指令被快速輪換執行,在宏觀上具備多個進程同時執行的效果。安全

線程是進程的執行單元,一個進程初始化後,主線程就被建立。線程能夠由本身的堆棧,程序計數器,和局部變量。但沒有系統資源。多個線程共享父進程的資源。多線程

一個進程中線程能夠併發執行,搶佔式執行。併發

操做系統能夠同時執行多個任務,每一個任務就是進程。進程能夠同時執行多個任務,每一個任務就是線程。框架

線程的建立和啓動異步

全部線程對象必須是Thread類或者子類的實例,線程的執行體表明線程的任務(一段程序流即一段順序執行的代碼)

1.定義Thread類的子類,並重寫run方法,run方法就是線程執行體

2.建立Thread子類的實例,即建立了線程對象

3.調用線程對象的start方法啓動多線程。

 

 

 

用繼承Thread類的方法建立的線程,多個線程之間沒法共享線程類的實例變量。

public class createByThread extends Thread{
    private  int i;
    public void run(){
        for(;i<100;i++){
            System.out.println(getName()+"  "+i);
        }
    }

    public static void main(String[] args) {
        for(var i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+" "+i);
            if(i==20){
                Thread th1=new createByThread();
                th1.setName("線程NO1");
                th1.start();
                new createByThread().start();
            }
            
        }
    }
}
線程NO1  0
線程NO1  1
線程NO1  2
線程NO1  3
線程NO1  4
Thread-1  0
線程NO1  5
Thread-1  1
線程NO1  6
Thread-1  2
線程NO1  7
Thread-1  3
線程NO1  8

  程序結果顯示,兩個線程各自有本身的私有成員變量i

實現Runnable接口建立線程類

1.定義Runnable接口的實現類,並重寫接口的run方法,該run方法時該線程的執行體

2.建立實現類的實例,做爲target

3建立Thread的實例,並用target作構造器的參數。

4調用線程對象的start()方法。

public class createByRunnable implements Runnable {

    private  int i=0;
    public void  run(){
        for(;i<100;i++){
            System.out.println(Thread.currentThread().getName()+"----"+i);
        }
    }

    public static void main(String[] args) {
        for(int i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+"----"+i);
            if(i==20){

                var rn1=new createByRunnable();
                Thread th3=new Thread(rn1,"新縣城1");
                Thread th4=new Thread(rn1,"新縣城2");
                th3.start();
                th4.start();
            }
        }
    }
}

  運行結果i是連續的。由於兩個線程共享一個Runnable對象target,因此多個線程能夠共享同一個線程類(實際上應該是線程的target類)的實例變量。

使用Callable和Future建立線程

run方法沒有返回值。爲了使得任意方法能夠做爲線程執行體,有了Callable接口。該接口有一個call方法,該方法有返回值。能夠做爲執行體。可是該方法不是直接被調用,返回值也不是直接返回。

使用Future接口,接口有一個實現類FutureTask類,該類做爲target,封裝了返回值。關聯了call方法。

建立啓動有返回值的線程步驟以下:

建立Callable接口的實現類,並實現Call方法,再建立實現類的實例。

使用FutureTask類保證Callable對象,封裝了call方法的返回值。

調用FutureTask對象get方法得到子線程執行結束後的返回值。

public static void main(String[] args) {
       //使用lambda表達式定義callable實現類對象,而且封裝爲task
        FutureTask<Integer> task=new FutureTask<>((Callable<Integer>)()->{
         var i=0;
         for(;i<100;i++){
             System.out.println(Thread.currentThread().getName()+"----"+i);
         }
         return  i;
        });
        for(var i=0;i<100;i++){
            System.out.println(Thread.currentThread().getName()+"----"+i);
            if(i==20){
                //task做爲target
                new Thread(task,"有返回值的方法").start();
            }
        }
        try{
            //獲取線程返回值
            System.out.println("子線程的返回值-----"+task.get());

        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

  

採用實現Runnable接口方式的多線程: 線程類只是實現了Runnable接口,還能夠能夠繼承其餘類。 在這種方式下,能夠多個線程共享同一個target對象,因此很是適合多個相同線程來處理同一份資源的狀況,從而能夠將CPU,代碼和數據分開,造成清晰的模型,較好地體現了面向對象的思想。 劣勢是:編程稍稍複雜,若是須要訪問當前線程,必須使用Thread.currentThread()方法。

採用繼承Thread類方式的多線程: 劣勢是:由於線程類已經繼承了Thread類,因此不能再繼承其餘父類。 優點是:編寫簡單,若是須要訪問當前線程,無需使用Thread.currentThread()方法,直接使用this便可得到當前線程。

線程的生命週期

 

 如圖所示,線程分爲新建,就緒,阻塞,運行,死亡五個聲明週期

new了線程以後,就處於新建。調用isAlive方法,會返回false,新建狀態沒有任何動態性能

當程序啓用了start方法,就進入就緒狀態,等待執行。

就緒狀態的線程得到了cpu,就開始執行run方法。

被cpu剝奪資源,就進入阻塞。

圖中寫出了引發阻塞的五個方法

調用yield方法,可讓運行狀態的線程轉入就緒狀態。

run()方法執行完成,線程正常結束。 線程拋出一個未捕獲的 Exception或Error。 直接調用該線程的stop()方法來結束該線程——該方法容易致使死鎖,一般不推薦使用。

主線程結束,不會影響其餘線程,地位相同。

不要從新啓動已經死亡的線程。

線程控制

join

當在線程執行程序中調用其餘線程的join方法後,會先執行這個線程,當他執行完或者等待了預約時間後,主線程開始執行

public class JoinThread extends Thread {
    public  JoinThread(String name){
        super(name);
    }
    public void run(){
        for(var i=0;i<100;i++){
            System.out.println(currentThread().getName()+"==="+i);
        }
    }
//使用join必須拋出異常或者使用try/catch
    public static void main(String[] args) throws InterruptedException {
        new JoinThread("第一子線程").start();

        for(var i=0;i<100;i++){
            if(i==20){
                var t1=new JoinThread("第二Join線程");
                //調用join前須要調用start
                t1.start();
                t1.join();
            }
            System.out.println(currentThread().getName()+"===="+i);
        }

    }
}



第二Join線程===94
第二Join線程===95
第二Join線程===96
第二Join線程===97
第二Join線程===98
第二Join線程===99
main====20
main====21
main====22
main====23
main====24

  後臺線程

調用Thread的setDaemon方法將線程設爲後臺線程。前臺線程死亡後,後臺線程自動死亡

前臺線程建立的線程默認爲前臺線程

後臺線程建立的線程默認爲後臺線程

前臺線程死亡,jvm會通知後臺線程死亡,但它從接收到指令作出響應,須要一段時間。

必須在線程啓動前,將線程設爲後臺線程。不然拋異常。

線程睡眠

sleep阻塞線程

yield將線程轉入就緒。從新讓系統的線程調度器調度一次。這是有可能該線程繼續被運行,有可能優先級比當前高的或者相同的處於就緒狀態的線程得到執行的機會

sleep方法暫停當前線程後,會給其餘線程執行機會,不會理會其餘線程的優先級。但yield方法只會給優先級相同,或優先級更高的線程執行機會。

sleep方法會將線程轉入阻塞狀態,直到通過阻塞時間纔會轉入就緒狀態。而yield不會將線程轉入阻塞狀態,它只是強制當前線程進入就緒狀態。所以徹底有可能某個線程調用yield方法暫停以後,當即再次得到處理器資源被執行。

sleep方法聲明拋出了InterruptedException異常,因此調用sleep方法時要麼捕捉該異常,要麼顯式聲明拋出該異常。而yield方法則沒有聲明拋出任何異常。

sleep方法比yield方法有更好的可移植性,一般不要依靠yield來控制併發線程的執行。

改變線程優先級

每一個線程執行都具備必定的優先級,優先級高的線程得到較多的執行機會。

每一個線程默認的優先級與建立他的父優先級相同。

Thread類提供了setPriority,1-10,可是與操做系統相關了之後,不能很好的對應

通常使用

MAX_PRIORITY:其值是10。

MIN_PRIORITY:其值是1。

NORM_PRIORITY:其值是5。

main線程具備普通優先級,即5.

線程同步

多個線程訪問同一個數據時,容易出現線程安全問題

Java的多線程支持引入了同步監視器來解決這個問題,使用同步監視器的通用方法就是同步代碼塊。 synchronized後括號裏的obj就是同步監視器,上面代碼的含義是:線程開始執行同步代碼塊以前,必須先得到對同步監視器的鎖定。

通常吧共享的資源,做爲obj

synchronized後括號裏的obj就是同步監視器,上面代碼的含義是:線程開始執行同步代碼塊以前,必須先得到對同步監視器的鎖定。

同步方法

同步方法時使用synchronized關鍵字來修飾某個方法。無須指定同步監視器,是this,即調用方法的對象。

經過同步方法能夠很方便的實現線程安全類

該類的對象能夠被多個線程安全的訪問。 每一個線程調用該對象的任意方法以後都將獲得正確結果。 每一個線程調用該對象的任意方法以後,該對象狀態依然保持合理狀態。

可變類的線程安全是以下降程序的運行效率做爲代價的,爲了減小線程安全所帶來的負面影響,程序能夠採用以下策略: 不要對線程安全類的全部方法都進行同步,只對那些會改變競爭資源(競爭資源也就是共享資源)的方法進行同步。例如上面的Account類中accountNo屬性就無需同步,因此程序只對draw方法進行同步控制。 若是可變類有兩種運行環境:單線程環境和多線程環境,則應該爲該可變類提供兩種版本:線程不安全版本和線程安全版本。在單線程環境中使用線程不安全版本以保證性能,在多線程環境中使用線程安全版本。

線程會在以下幾種狀況下釋放對同步監視器的鎖定: 當前線程的同步方法、同步代碼塊執行結束,當前線程即釋放同步監視器。 當線程在同步代碼塊、同步方法中遇到break、return終止了該代碼塊、該方法的繼續執行,當前線程將會釋放同步監視器。 當線程在同步代碼塊、同步方法中出現了未處理的Error或Exception,致使了該代碼塊、該方法異常結束時將會釋放同步監視器。 當線程執行同步代碼塊或同步方法時,程序執行了同步監視器對象的wait()方法,則當前線程暫停,並釋放同步監視器。

線程執行同步代碼塊或同步方法時,調用sleep,ield方法暫停執行,不會釋放同步監視器

當其餘線程調用了該線程的suspend方法,掛起線程時,不釋放同步監視器。

同步鎖Lock

Lock是控制多個線程對共享資源進行訪問的工具。一般,鎖提供了對共享資源的獨佔訪問,每次次只能有一個線程對Lock對象加鎖,線程開始訪問共享資源以前應先得到Lock對象。不過,某些鎖可能容許對共享資源併發訪問,如 ReadWriteLock(讀寫鎖)。固然,在實現線程安全的控制中,一般喜歡使用ReentrantLock(可重入鎖)。使用該Lock對象能夠顯式地加鎖、釋放鎖。 ReentrantLock鎖具備可重入性,也就是說線程能夠對它已經加鎖的ReentrantLock鎖再次加鎖,ReentrantLock對象會維持一個計數器來追蹤lock方法的嵌套調用,線程在每次調用lock()方法加鎖後,必須顯式調用unlock()方法來釋放鎖,因此一段被鎖保護的代碼能夠調用另外一個被相同鎖保護的方法

當兩個線程相互等待對方釋放同步監視器時就會發生死鎖,Java虛擬機沒有監測、也沒有采用措施來處理死鎖狀況,因此多線程編程時應該採起措施避免死鎖的出現。一旦出現死鎖,整個程序既不會發生任何異常,也不會給出任何提示,只是全部線程處於阻塞狀態,沒法繼續

線程通訊

線程通訊必定創建在線程安全的基礎上

傳統的線程通訊

wait():致使當前線程等待,直到其餘線程調用該同步監視器的notify()方法或notifyAll()方法來喚醒該線程。該wait()方法有三種形式:無時間參數的wait(一直等待,直到其餘線程通知),帶毫秒參數的wait和帶毫秒、微秒參數的wait(這兩種方法都是等待指定時間後自動甦醒)。調用wait()方法的當前線程會釋放對該同步監視器的鎖定。

notify():喚醒在此同步監視器上等待的單個線程。若是全部線程都在此同步監視器上等待,則會選擇喚醒其中一個線程。選擇是任意性的。只有當前線程放棄對該同步監視器的鎖定後(使用wait()方法),才能夠執行被喚醒的線程。

notifyAll():喚醒在此同步監視器上等待的全部線程。只有當前線程放棄對該同步監視器的鎖定後,才能夠執行被喚醒的線程。

使用Condition控制線程通訊

當使用Lock對象來保證同步時,Java提供了一個Condition類來保持協調,使用Condition可讓那些已經獲得Lock對象、卻沒法繼續執行的線程釋放Lock對象,Condtion對象也能夠喚醒其餘處於等待的線程。 Condition 將同步監視鎖方法(wait、notify 和 notifyAll)分解成大相徑庭的對象,以便經過將這些對象與Lock對象組合使用,爲每一個對象提供多個等待集(wait-set)。在這種狀況下,Lock 替代了同步方法或同步代碼塊,Condition替代了同步監視鎖的功能。 Condition實例實質上被綁定在一個Lock對象上。要得到特定Lock實例的Condition實例,調用Lock對象newCondition()方法便可。Condtion類提供了以下三個方法: await():相似於隱式同步監視器上的wait()方法,致使當前線程等待,直到其餘線程調用該Condtion的signal ()方法或signalAll ()方法來喚醒該線程。該await方法有更多變體:long awaitNanos(long nanosTimeout)、void awaitUninterruptibly()、awaitUntil(Date deadline)等,能夠完成更豐富的等待操做。 signal ():喚醒在此Lock對象上等待的單個線程。若是全部線程都在該Lock對象上等待,則會選擇喚醒其中一個線程。選擇是任意性的。只有當前線程放棄對該Lock對象的鎖定後(使用await()方法),才能夠執行被喚醒的線程。 signalAll():喚醒在此Lock對象上等待的全部線程。只有當前線程放棄對該該Lock對象的鎖定後,才能夠執行被喚醒的線程。

使用阻塞隊列控制線程通訊

java5提供了一個BlockingQueue接口,雖然是queue的子接口,可是用途是線程通訊。

當生產者線程試圖向BlockingQueue中放入元素時,若是隊列已滿,則線程被阻塞。put方法

當消費者線程試圖向BlockingQueue中取出元素時,若是隊列已空,則線程阻塞。take方法

由於繼承queue接口

add,offer,put方法爲在尾部插入元素。滿則阻塞false

remove,poll,take在頭部取出元素並刪除。空則阻塞 false

element,peek,在頭部取出但不刪除。空則跑異常。返回false

ArrayBlockingQueue基於數組實現的

LinkedBlockingQueue基於鏈表實現的

PriorityBlockingQueue 不是取出隊列中存在時間最長的元素,而是隊列中最小的元素。實現了Comparable接口

SynchronousQueue同步隊列,對該隊列的存取操做必須交替進行

DelayQueue 底層基於priorityBlockingqueue實現,要求集合元素都實現Delay接口,接口有一個long getDelay方法,根據集合元素的getDalay方法返回值進行排序。

線程組合未處理的異常

若是用戶建立的線程沒有指定線程組,則輸與默認線程組。

Java使用ThreadGroup來表示線程組,它能夠對一批線程進行分類管理,Java容許程序直接對線程組進行控制。 一旦某個線程加入了指定線程組以後,該線程將一直屬於該線程組,直到該線程死亡,線程運行中途不能改變它所屬的線程組。 Thread類提供了以下幾個構造器來設置新建立的線程屬於哪一個線程組: Thread(ThreadGroup group, Runnable target):以target的run方法做爲線程執行體建立新線程,屬於group線程組。 Thread(ThreadGroup group, Runnable target, String name):以target的run方法做爲線程執行體建立新線程,該線程屬於group線程組,且線程名爲name。 Thread(ThreadGroup group, String name):建立新線程,新線程名爲name,屬於group線程組。

Thread類沒有提供setThreadGroup的方法來改變線程所屬的線程組,但提供了一個getThreadGroup()方法來返回該線程所屬的線程組,getThreadGroup()方法的返回值是ThreadGroup對象,表示一個線程組。ThreadGroup類有以下兩個簡單的構造器來建立實例: ThreadGroup(String name):以指定線程組名字來建立新的線程組。 ThreadGroup(ThreadGroup parent, String name):以指定的名字、指定的父線程組建立一個新線程組。

從JDK1.5開始,Java增強了線程的異常處理,若是線程執行過程當中拋出了一個未處理的異常,JVM在結束該線程以前會自動查找是否有對應的Thread.UncaughtExceptionHandler對象,若是找到該處理器對象,將會調用該對象的uncaughtException(Thread t, Throwable e)方法來處理該異常。 Thread.UncaughtExceptionHandler是Thread類的一個內部公共靜態接口,該接口內只有一個方法:void uncaughtException(Thread t, Throwable e),該方法中的t表明出現異常的線程,而e表明該線程拋出的異常。

(1)若是該線程組有父線程組,則調用父線程組的uncaughtException方法來處理該異常。

(2)若是該線程實例所屬的線程類有默認的異常處理器(由setDefaultUncaughtExceptionHandler方法設置的異常處理器),那就調用該異常處理器來處理該異常。

(3)若是該異常對象是ThreadDeath的對象,將不作任何處理;不然將異常跟蹤棧的信息打印到System.err錯誤輸出流,並結束該線程。

線程池

系統啓動一個新線程的成本是比較高的,由於它涉及到與操做系統交互。在這種情形下,使用線程池能夠很好地提升性能,尤爲是當程序中須要建立大量生存期很短暫的線程時,更應該考慮使用線程池。 與數據庫鏈接池相似的是,線程池在系統啓動時即建立大量空閒的線程,程序將一個Runnable對象傳給線程池,線程池就會啓動一條線程來執行該對象的run方法,當run方法執行結束後,該線程並不會死亡,而是再次返回線程池中成爲空閒狀態,等待執行下一個Runnable對象的run方法。

JDK1.5提供了一個Executors工廠類來產生線程池,該工廠類裏包含以下幾個靜態工廠方法來建立鏈接池: newCachedThreadPool():建立一個具備緩存功能的線程池,系統根據須要建立線程,這些線程將會被緩存在線程池中。 newFixedThreadPool(int nThreads):建立一個可重用的、具備固定線程數的線程池。 newSingleThreadExecutor():建立一個只有單線程的線程池,它至關於newFixedThreadPool方法時傳入參數爲1。 newScheduledThreadPool(int corePoolSize):建立具備指定線程數的線程池,它能夠在指定延遲後執行線程任務。corePoolSize指池中所保存的線程數,即便線程是空閒的也被保存在線程池內。 newSingleThreadScheduledExecutor():建立只有一條線程的線程池,它能夠在指定延遲後執行線程任務。

ExecutorService

表明儘快執行線程的線程池(只要線程池中有空閒線程當即執行線程任務),程序只要將一個Runnable對象或Callable對象(表明線程任務)提交給該線程池便可,該線程池就會盡快執行該任務。ExecutorService裏提供了以下三個方法: Future<?> submit(Runnable task):將一個Runnable對象提交給指定的線程池。線程池將在有空閒線程時執行Runnable對象表明的任務。其中Future對象表明Runnable任務的返回值——但run方法沒有返回值,因此Future對象將在run方法執行結束後返回null。但能夠調用Future的isDone()、isCancelled()方法來得到Runnable對象的執行狀態。 <T> Future<T> submit(Runnable task, T result):將一個Runnable對象提交給指定的線程池。線程池將在有空閒線程時執行Runnable對象表明的任務,result顯式指定線程執行結束後的返回值。,因此Future對象將在run方法執行結束後返回result。 <T> Future<T> submit(Callable<T> task):將一個Callable對象提交給指定的線程池。線程池將在有空閒線程時執行Callable對象表明的任務,Future表明Callable對象裏call方法的返回值。

ScheduledExecutorService

表明可在指定延遲,或週期性執行線程任務的線程池,它提供了以下四個方法: ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit):指定callable任務將在delay延遲後執行。 ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit):指定command任務將在delay延遲後執行。 ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit):指定command任務將在delay延遲後執行,並且以設定頻率重複執行。也就是說,在initialDelay後開始執行,依次在 initialDelay+period 、initialDelay + 2 * period...處重複執行,依此類推。 ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit):建立並執行一個在給定初始延遲後首次啓用的按期操做,隨後,在每一次執行終止和下一次執行開始之間都存在給定的延遲。若是任務的任一次執行時遇到異常,就會取消後續執行。不然,只能經過程序來顯式取消或終止來終止該任務。

使用線程池的步驟

(1)調用Executors類的靜態工廠方法建立一個ExecutorService對象或ScheduledExecutorService對象,其中前者表明簡單的線程池,後者表明能以任務調度方式執行線程的線程池。

(2)建立Runnable實現類或Callable實現類的實例,做爲線程執行任務。

(3)調用ExecutorService對象的submit方法來提交Runnable實例或Callable實例;或調用ScheduledExecutorService的schedule來執行線程。

(4)當不想提交任何任務時調用ExecutorService對象的shutdown方法來關閉線程池。

使用ForkJoinPool利用多核cpu

java7提供了ForkJoinPool來支持將一個任務拆分紅多個小人物,並行計算。再把多個小任務的結果合併成總的計算結果。ForkJoinPool是ExecutorService的實現類,所以是一種特殊的線程池。

java8進一步擴展了它的功能。增長了通用池的功能。

commonPool 返回一個通用池,運行狀態不收shutdown方法影響

getCommonPollParallelism 返回通用池的並行級別

建立了ForkJoinPool以後,就能夠調用submit或invoke方法來執行任務。ForkJoinTask表明一個能夠並行,合併的任務。

線程相關類

ThreadLocal

線程局部變量類。

爲每個使用該變量的線程都提供一個變量的副本,使每個線程均可以獨立改變本身的副本

get,remove set方法

這個方法和同步機制有區別,不能替代

若是多個線程之急須要共享資源,已帶到線程之間的通訊功能,就是用同步機制

若是僅僅須要隔離多個線程之間的共享衝突,則可使用ThreadLocal。

包裝線程不安全集合

若是程序有多條線程可能訪問以上ArrayList、HashMap等集合,可使用Collections提供的靜態方法來把這些集合包裝成線程安全的集合。Collections提供了以下幾個靜態方法:

static <T> Collection<T> synchronizedCollection(Collection<T> c):返回指定 collection 對應的線程安全的collection。

static <T> List<T> synchronizedList(List<T> list):返回指定List對應的線程安全的List對象。

static <K,V> Map<K,V> synchronizedMap(Map<K,V> m):返回指定Map對象對應的線程安全的Map對象。

static <T> Set<T> synchronizedSet(Set<T> s):返回指定Set對應的線程安全的Set。

static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m):返回指定SortedMap對象對應的線程安全的SortedMap對象。

static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s):返回指定SortedSet對象對應的線程安全的SortedSet對象。

線程安全的集合類

java.util.concurrent包下提供了提供了ConcurrentHashMap、ConcurrentLinkedQueue兩個支持併發訪問的集合,它們分別表明了支持併發訪問的HashMap和支持併發訪問的Queue。

ConcurrentLinkedQueue不容許使用null元素,實現類多線程的高效訪問,無須等待

ConcurrentHashMap支持16個線程併發訪問。

java8擴展了ConcurrentHashMap的功能

CopyOnWriteArrrayList寫入操做會複製一份副本,所以效率比較低,因此適合讀取遠遠大於寫入操做的場景。

java9新增的發佈訂閱框架

Java 9新增了一個發佈-訂閱框架,這個發佈-訂閱框架是基於異步響應流的。這個發佈-訂閱框架能夠很是方便地處理異步線程之間的流數據交換(好比兩個線程之間須要交換數據)。並且這個發佈-訂閱框架不須要使用數據中心來緩衝數據,同時具備很是高效的性能。 這個發佈-訂閱框架使用Flow類的四個靜態內部接口做爲核心API: Flow.Publisher:表明數據發佈者、生產者。 Flow.Subscriber:表明數據訂閱者、消費者。 Flow.Subscription:表明發佈者和訂閱者之間的連接紐帶。訂閱者經過調用該對象的request()方法來獲取 Flow.Processor:數據處理器,它可同時做爲發佈者和訂閱者使用。 Flow.Subscriber接口定義了以下方法。 void onSubscribe(Flow.Subscription subscription):訂閱者註冊時自動觸發該方法。 void onComplete():當訂閱結束時觸發發該方法。 void onError(Throwable throwable):訂閱失敗時觸發該方法。 void onNext(T item):訂閱者從發佈者處獲取數據項觸發該方法,訂閱者可經過該方法獲取數據項。

相關文章
相關標籤/搜索