日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Java線程學(xué)習(xí)和總結(jié)

 shaobin0604@163.com 2007-01-11
 

線程是Java的一大特色,從語言上直接支持線程,線程對(duì)于進(jìn)程來講的優(yōu)勢(shì)在于創(chuàng)建的代價(jià)很小,上下文切換迅速,當(dāng)然其他的優(yōu)勢(shì)還有很多,缺點(diǎn)也是有的,比如說對(duì)于開發(fā)人員來講要求比較高,不容易操作,但是Java的線程的操作已經(jīng)簡(jiǎn)化了很多,是一個(gè)比較成熟的模型。很多時(shí)候,我們都用不到線程,但是當(dāng)我們有一天不走運(yùn)(或者走運(yùn))的時(shí)候,我們必須要面對(duì)這個(gè)問題的時(shí)候,應(yīng)該怎么辦呢?本文是我的學(xué)習(xí)筆記和一些總結(jié),試圖解決這個(gè)問題,引領(lǐng)還沒有接觸過Java 線程的開發(fā)人員進(jìn)入一個(gè)Java線程的世界,其實(shí)很多東西在網(wǎng)路上已經(jīng)有朋友總結(jié)過了,不過我感覺沒有比較循序漸進(jìn),要么太基礎(chǔ),要么太高深,所以這邊我由淺到深的總結(jié)一下。但是很顯然,我的資歷尚淺,能力也很有限,如果有什么錯(cuò)誤還望不吝賜教!麻煩發(fā)送mail到:fantian830211@163.com 而且,這些大部份的都有源碼,如果需要也可以發(fā)mail到這個(gè)郵箱,真的非常希望有人能指正我的錯(cuò)誤!

(一) 基本的API介紹

1.   如何創(chuàng)建一個(gè)可以執(zhí)行的線程類

       創(chuàng)建一個(gè)線程有兩個(gè)辦法:繼承Thread類或者實(shí)現(xiàn)Runnable接口。

       首先:繼承Thread

       這里一般只需要我們來重寫run這個(gè)方法。下面是代碼:

public class SimpleThread extends Thread {

       public SimpleThread() {

              start();

       }

       @Override

    public void run() {

              while (true) {

                     System.out.println(this);

                     // Imply other thread can run now, but we cannot assume that it will

                     // work well every time, actually , most of time we can get the same

                     // result, but not to a certainty.

                     // yield();

                     try {

                            sleep(100);

                     } catch (InterruptedException e) {

                            e.printStackTrace();

                     }

              }

       }

}

其次:實(shí)現(xiàn)Runnable接口,代碼如下:

       Public class Inner implements Runnable {

              private Thread thread;

              public Inner(String name) {

                     thread = new Thread(this, name);

                     thread.start();

              }

              public void run() {

                     while (true) {

                     try {

                                   Thread.sleep(10);

                            } catch (InterruptedException e) {

                                   throw new RuntimeException(e);

                            }

                     }

              }

2.   幾個(gè)常用的API

這邊介紹幾個(gè)常見而且重要的的線程API,這邊JDK文檔有更加詳細(xì)的說明,其實(shí)JDK的文檔就是個(gè)很好的學(xué)習(xí)資料,常備很重要哦!

方法

說明

start

使線程開始執(zhí)行,實(shí)際上這個(gè)方法會(huì)調(diào)用下面的run這個(gè)方法,如果這個(gè)線程已經(jīng)開始執(zhí)行,則會(huì)扔出IllegalThreadStateException

sleep

是當(dāng)前已經(jīng)運(yùn)行的線程休眠一段時(shí)間。如果當(dāng)前線程已經(jīng)被別的線程中斷的話,將會(huì)扔出InterruptedException,而且interrupted標(biāo)志也會(huì)被清空。這個(gè)方法有兩個(gè)版本,具體參看JDK文檔。

run

線程執(zhí)行的業(yè)務(wù)邏輯應(yīng)該在這里實(shí)現(xiàn)。

join

等待另外一個(gè)線程死亡。如果當(dāng)前線程已經(jīng)被別的線程中斷的話,將會(huì)扔出InterruptedException,而且interrupted標(biāo)志也會(huì)被清空。

yield

使當(dāng)前線程臨時(shí)的中斷執(zhí)行,來允許其他線程可以執(zhí)行,因?yàn)?/span>Java的線程模型實(shí)際上映射到操作系統(tǒng)的線程模型,所以對(duì)于不同的操作系統(tǒng),這個(gè)方法的就有不同的意義。對(duì)于非搶占式Operating System,這個(gè)方法使得其他線程得到運(yùn)行的機(jī)會(huì),但是對(duì)于搶占式的OS,這個(gè)方法沒有太多的意義。關(guān)于這個(gè)方法,后邊還有更多的介紹。

wait

Wait方法和后邊的兩個(gè)方法都來自Object。看過Java源碼的可以知道,這三個(gè)方法都是Native方法,使比較直接的和操作系統(tǒng)打交道的方法。

這個(gè)方法的作用是讓當(dāng)前線程等待,直到被喚醒或者等待的時(shí)間結(jié)束。當(dāng)前線程進(jìn)入等待隊(duì)列的時(shí)候,會(huì)放棄當(dāng)前所有的資源,所以當(dāng)前線程必須獲得這些對(duì)象的Monitor,否則會(huì)扔出IllegalMonitorStateException 關(guān)于wait方法的更多,后邊會(huì)有介紹到。

notify

通知其他線程可以使用資源了。這個(gè)方法的使用要求很多,總之需要當(dāng)前線程獲得被調(diào)用的notify方法的對(duì)象的monitor。比如:

                                                 synchronized (person) {

                                                        person.notify();

                                                 }

其實(shí),獲得monitor的方法還有別的,這里簡(jiǎn)單介紹一下:

1.         執(zhí)行這個(gè)對(duì)象的一個(gè)同步的方法

2.         執(zhí)行這個(gè)對(duì)象的同步塊

3.         執(zhí)行一個(gè)同步的靜態(tài)方法

notifyAll

除了通知所有的線程可以準(zhǔn)備執(zhí)行之外,跟上面的方法要求一樣。但是只有一個(gè)線程會(huì)被選擇然后執(zhí)行,這個(gè)就跟優(yōu)先級(jí)和其他狀態(tài)有關(guān)系了。

interrupt

中斷線程。

這邊只是介紹了幾個(gè)常用的API,但是非常重要,其他的API可以查看JDK的相關(guān)文檔。但是在操作系統(tǒng)的概念中,很顯然,對(duì)于一個(gè)線程應(yīng)該還有別的狀態(tài),對(duì),確實(shí)還有,但是Java在實(shí)現(xiàn)的映射的時(shí)候,也實(shí)現(xiàn)了這些方法,只是不贊成使用,下面的主題將討論這些方法以及這些方法的替代方法。

3.   已經(jīng)不贊成使用的方法

對(duì)于一些不應(yīng)該再使用的東西,有時(shí)候被稱為反模式antipattern。這些都是概念上的東西,對(duì)于我們開發(fā)人員來講,需要做的就是寫出好的代碼。

方法

說明

stop

強(qiáng)制使當(dāng)前的線程停止執(zhí)行。實(shí)際上,作為開發(fā)人員我們會(huì)意識(shí)到,線程的復(fù)雜程度是沒有邊際的,而這個(gè)方法這樣武斷的停止一個(gè)線程,必然導(dǎo)致問題產(chǎn)生。也就是說,這個(gè)方法天生就有問題。比如說一個(gè)線程掌握了很多對(duì)象,并且改變了其中一些的狀態(tài),如果突然當(dāng)前對(duì)象突然被停止,將會(huì)釋放這些對(duì)象的monitor,這個(gè)時(shí)候被改變狀態(tài)的對(duì)象就是被損壞的對(duì)象,其他線程再來操作的時(shí)候問題就出來了。

替代的辦法就是讓當(dāng)前線程正常結(jié)束,不使用這個(gè)方法。就是我們?cè)O(shè)置一些標(biāo)志,如果這些標(biāo)志滿足的時(shí)候,我們結(jié)束線程。下面用JDK的例子:

    private Thread blinker;

    public void start() {

        blinker = new Thread(this);

        blinker.start();

    }

    public void stop() {

        blinker.stop();  // UNSAFE!

    }

    public void run() {

        Thread thisThread = Thread.currentThread();

        while (true) {

            try {

                thisThread.sleep(interval);

            } catch (InterruptedException e){

            }

            //do something

        }

}

修改后:

    private volatile Thread blinker;
    public void stop() {
        blinker = null;
    }
    public void run() {
        Thread thisThread = Thread.currentThread();
        //Check the flag
        while (blinker == thisThread) {
            try {
                thisThread.sleep(interval);
            } catch (InterruptedException e){
            }
            //do something
        }

}

當(dāng)然如果這個(gè)方法中間有wait方法的調(diào)用的話,而且正在等待,我們可以使用這個(gè)辦法來結(jié)束:

Thread.currentThread().interrupt();

然后處理InterruptedException

 

這個(gè)我也實(shí)現(xiàn)了避免使用stop方法的一個(gè)類,在源碼中可以看到。

suspend

這個(gè)方法天生就有導(dǎo)致死鎖的可能。如果當(dāng)前線程持有很多對(duì)象的鎖,但是當(dāng)他suspend的時(shí)候,這些鎖是不會(huì)釋放的,想想就知道應(yīng)該什么可能會(huì)發(fā)生,所以這個(gè)方法應(yīng)該盡量不用。

這里我們有辦法替代這個(gè)方法,其實(shí)根替代stop的方法差不多,就是用wait方法來實(shí)現(xiàn)掛起,而不是事實(shí)上的掛起。比如:

@Override

    @SuppressWarnings("static-access")

                            public void run() {

                                   while (true) {

                                          try {

                                                 Thread.currentThread().sleep(1000);

                                                 // Double check

                                                 if (isSuspended) {

                                                        synchronized (this) {

                                                               while (isSuspended) {

                                                                      wait();

                                                               }

                                                        }

                                                 }

                                          } catch (InterruptedException e) {

                                                 // null

 

                                          }

                                   }

                            }

    這樣做可以同樣實(shí)現(xiàn)掛起,但是仍然會(huì)釋放資源。

resume

很顯然,這個(gè)方法和上面的方法是對(duì)應(yīng)的,所以上面用了wait方法來替代,所以這邊應(yīng)該用notify這個(gè)方法或者notifyAll這個(gè)方法來替代。

 

其實(shí)這邊可以把上面的實(shí)現(xiàn)方式結(jié)合起來,實(shí)現(xiàn)一個(gè)可以安全stopsuspend的線程。這個(gè)在我的源碼里有實(shí)現(xiàn),但是不知道是不是對(duì)的。不過感覺原則應(yīng)該沒有問題,那就是設(shè)置標(biāo)志來結(jié)束或者掛起線程,而不是使用這些過時(shí)的方法。

4.   跟線程相關(guān)的關(guān)鍵字

跟線程相關(guān)的關(guān)鍵字我能夠想到的就下面兩個(gè):

關(guān)鍵字

說明

volatile

這個(gè)關(guān)鍵字告訴編譯器不要對(duì)這個(gè)屬性或者值進(jìn)行優(yōu)化,也就是為了保證這個(gè)變量的同步性,如果這個(gè)值被更新,其他線程應(yīng)該可以馬上訪問到最新的值,而不是“臟值”。其實(shí)這個(gè)關(guān)鍵字是同步互斥的一個(gè)模型,但是現(xiàn)在沒有實(shí)現(xiàn)。

synchronized

給對(duì)象或者Class加鎖,分為對(duì)象鎖和Class鎖。

對(duì)象鎖只是加在當(dāng)前對(duì)象上,對(duì)別的對(duì)象沒有影響,這種加鎖一般都是把這個(gè)關(guān)鍵字用在方法和同步塊上面。

Class鎖就是加在這個(gè)Class上面,所有的其他對(duì)象想訪問這個(gè)Class的對(duì)象的任何同步方法,必須獲得這個(gè)鎖。這種鎖一般把這個(gè)關(guān)鍵字用在靜態(tài)方法中,或者顯示的這樣實(shí)現(xiàn):

                                   synchronized (AClass.class) {

                                          while (isSuspended) {

                                                 wait();

                                          }

                                   }

一般我們很少用Class鎖。

 

這里簡(jiǎn)單提一下monitor,個(gè)人感覺這里把monitor認(rèn)為是一把鎖也可以。網(wǎng)絡(luò)上有朋友解釋的比較好:在java中,每個(gè)對(duì)象只有一個(gè)相應(yīng)的monitor,一個(gè)mutex,而每一個(gè)monitor都可以有多個(gè)“doors”可以進(jìn)入,即,同一個(gè)monitor中被守護(hù)的代碼可以在不同的地方,因?yàn)橥粋€(gè)對(duì)象可以出現(xiàn)在不同的代碼段,只要mutex鎖定的對(duì)象是同一個(gè),每個(gè)入口都用Synchronized關(guān)鍵字表明,當(dāng)一個(gè)線程通過了Synchronized關(guān)鍵字,它就所住了該monitor所有的doors

其實(shí)線程的使用不在于語言的API,而在于對(duì)操作系統(tǒng)的理解和一些常見的調(diào)度算法,其實(shí)個(gè)人理解經(jīng)驗(yàn)比較重要,后邊介紹到線程的實(shí)現(xiàn)模式和設(shè)計(jì)模式。其實(shí)我還是以前的想法:對(duì)于語言的學(xué)習(xí),首先學(xué)習(xí)語法和API,然后學(xué)習(xí)如何使用這些API在語法的框架內(nèi)編寫出高效的程序。很顯然,模式就是實(shí)現(xiàn)后邊的重要方法。模式常見的分類有實(shí)現(xiàn)模式、設(shè)計(jì)模式和架構(gòu)模式。這里限于本人的能力問題,沒有理解到架構(gòu)上面去,所以這里只是研究了前兩個(gè)。

(二) 線程實(shí)現(xiàn)模式

實(shí)現(xiàn)模式這邊主要參考自Effective Java這本書,至少分類是,但是很多內(nèi)容應(yīng)該會(huì)很不相同,當(dāng)然還有Think in java。Effective Java短小精悍的一本書,其中有太多的Java的關(guān)于實(shí)現(xiàn)模式的建議,但是這邊把這本書的內(nèi)容歸類到實(shí)現(xiàn)模式,是我個(gè)人的想法,如果有什么不正確,萬望指正。但是,個(gè)人認(rèn)為這些概念性的東西仍然不會(huì)損害到我們需要討論的問題的實(shí)質(zhì)。

1.         共享數(shù)據(jù)同步

上面有提到過synchronized關(guān)鍵字,這個(gè)關(guān)鍵字保證一段代碼同時(shí)只能有一個(gè)線程在執(zhí)行,保證別人不會(huì)看到對(duì)象處于不一致的狀態(tài)中。對(duì)象將從一種一致的狀態(tài)轉(zhuǎn)變到另一種一致的狀態(tài),后來的線程將會(huì)看到后一種狀態(tài)。

Java中,虛擬機(jī)保證原語類型(doublelong)的讀寫都是原子性的。即不需要同步,但是如果不對(duì)這樣的數(shù)據(jù)讀寫進(jìn)行同步,那么后果將很嚴(yán)重。可以參照Effective Java的解釋,這里還要簡(jiǎn)單的提示意下,Effective Java中有提到double check這種方式,而且我的源代碼中多次用到這種方法,單是需要提醒一下,如果用這種方式來實(shí)現(xiàn)singleton的話,就不可以了,因?yàn)檫@樣有可能導(dǎo)致不完整的對(duì)象被使用,單是源碼中的double check用的都是原語類型,所以OK。 這邊的建議是如果修改原語類型或者非可變類的屬性,可以同步或者使用volatile關(guān)鍵字。如果是其他對(duì)象,必須同步。關(guān)于盡量少使用同步,這邊的建議是,我們這樣的初學(xué)者在不知道如何優(yōu)化的情況下就不要優(yōu)化,我們要的是正確的程序,而不是快的程序。

2.         wait方法的使用

wait方法是一個(gè)很重要的方法,前面有介紹過這個(gè)方法,不但可以使一個(gè)線程等待,而且可以作為實(shí)現(xiàn)suspend的替代方法的一個(gè)方法。

Wait方法的標(biāo)準(zhǔn)使用方式如下:

                                   synchronized (obj) {

                                          while (condition)

                                                 wait();

                                   }

這里,對(duì)應(yīng)wait方法還有一個(gè)notifynotifyAll方法,到底我們應(yīng)該如何使用這兩個(gè)方法來喚醒等待的線程呢?很顯然notifyAll的使用是最安全的,但是會(huì)帶來性能的降低。這里又提到我們初學(xué)者,應(yīng)該優(yōu)先考慮這個(gè)方法,而不是notify。

3.         不要依賴線程調(diào)度器,管好自己的事情

Thread.yield這個(gè)方法并不能保證線程的公平運(yùn)行,所以這個(gè)方法不應(yīng)該依賴。還有就是線程的優(yōu)先級(jí),Java的線程優(yōu)先級(jí)有10個(gè)等級(jí),但是這個(gè)等級(jí)幾乎沒有什么用處,所以我們也不應(yīng)該依賴這個(gè)優(yōu)先級(jí)來控制程序,當(dāng)然仍然可以優(yōu)化一些服務(wù),但是不能保證這些服務(wù)一定被優(yōu)化了。我們應(yīng)該盡量控制對(duì)critical resources的方法線程數(shù),而不是用優(yōu)先級(jí)或者yield來實(shí)現(xiàn)對(duì)資源的訪問。

4.         不要使用線程組

線程組是一個(gè)過時(shí)的API,所以不建議使用。但是也不是一無是處,“存在即合理”嘛!

(三) 線程設(shè)計(jì)模式

什么是模式呢?Martin Flower先生這樣描述:一個(gè)模式,就是在實(shí)際的上下文中,并且在其他上下文中也會(huì)有用的想法。

這邊的線程設(shè)計(jì)模式大部分參考自林信良先生的《設(shè)計(jì)模式》,還有一些網(wǎng)路的文章,這些都是前輩們?cè)谑褂镁€程時(shí)候的經(jīng)驗(yàn),非常值得我們借鑒。還有就是林信良先生的設(shè)計(jì)模式非常通俗易懂,是入門級(jí)選手的最佳選擇。關(guān)于線程的模式應(yīng)該還有別的,只是我這邊現(xiàn)在只能總結(jié)這么多了,能力有限。這邊用大量的UML來描述這些模式,但是由于我的UML學(xué)的不好,而且工具用的不怎么熟,畫的圖應(yīng)該會(huì)有些問題,當(dāng)做草圖來看就好了。

1.         Single Threaded Execution

這個(gè)模式在Java里說的話有點(diǎn)多余,但是這邊還是先拿這個(gè)開胃一下。很明顯,從字面的意思,就是說同一時(shí)刻只有一個(gè)線程在執(zhí)行,Java里用synchronized這個(gè)關(guān)鍵字來實(shí)現(xiàn)這個(gè)模式。確實(shí)多余 L!看看UML吧!其實(shí)用這個(gè)圖來描述有點(diǎn)不好。其實(shí)應(yīng)該用別的圖來描述會(huì)比較好!比如協(xié)作圖。

2.         Guarded Suspension

網(wǎng)上有一個(gè)比較好的描述方式:要等我準(zhǔn)備好噢!

這里我們假設(shè)一種情況:一個(gè)服務(wù)器用一個(gè)緩沖區(qū)來保存來自客戶端的請(qǐng)求,服務(wù)器端從緩沖區(qū)取得請(qǐng)求,如果緩沖區(qū)沒有請(qǐng)求,服務(wù)器端線程等待,直到被通知有請(qǐng)求了,而客戶端負(fù)責(zé)發(fā)送請(qǐng)求。

很顯然,我們需要對(duì)緩沖區(qū)進(jìn)行保護(hù),使得同一時(shí)刻只能有一個(gè)服務(wù)器線程在取得request,也只能同一時(shí)刻有一個(gè)客戶端線程寫入服務(wù)。

UML描述如下:

具體實(shí)現(xiàn)可以參看代碼。

但是,這個(gè)模式有一點(diǎn)點(diǎn)瑕疵,那就是緩沖區(qū)沒有限制,對(duì)于有的情況就不會(huì)合適,比如說您的緩沖區(qū)所能占用的空間受到限制。下面的Producer Consumer Pattern應(yīng)該會(huì)有所幫助。

3.         Producer Consumer

Producer Consumer跟上面的Guarded Suspension很像,唯一的區(qū)別在于緩沖區(qū),Guarded Suspension模式的緩沖區(qū)沒有限制,所以,他們適用的場(chǎng)合也就不一樣了,很顯然,這個(gè)考慮應(yīng)該基于內(nèi)存是否允許。Producer Consumer的緩沖區(qū)就像一個(gè)盒子,如果裝滿了,就不能再裝東西,而等待有人拿走一些,讓后才能繼續(xù)放東西,這是個(gè)形象的描述??梢詤⒖枷旅娴?/span>UML,然后具體可以參看源碼。

4.         Worker Thread

Worker Thread與上面的Producer-consumer模式的區(qū)別在于Producer-consumer只是專注于生產(chǎn)與消費(fèi),至于如何消費(fèi)則不管理。其實(shí)Worker Thread模式是Producer-consumerCommand模式的結(jié)合。這邊簡(jiǎn)單描述一下Command patternUML就和衣很清晰的描述Command pattern

這個(gè)模式在我們的很多MVC框架中幾乎都會(huì)用到,以后我也想寫一個(gè)關(guān)于Web應(yīng)用的總結(jié),會(huì)提到具體的應(yīng)用。其實(shí)Command pattern模式的核心就是針對(duì)接口編程,然后存儲(chǔ)命令,根據(jù)客戶短的請(qǐng)求取得相應(yīng)的命令,然后執(zhí)行,這個(gè)跟我們的Web請(qǐng)求實(shí)在是太像了,其實(shí)Struts就是這樣做的,容器相當(dāng)于Client,然后控制器Servlet相當(dāng)于Invoker,Action相當(dāng)于ICommand,那么Receiver相當(dāng)于封裝在Action中的對(duì)象了,比如Request等等。

上面描述過Command pattern之后,我們回到Worker模式。

這邊看看workerUML

從圖中可以看到,CommandBuffer這個(gè)緩沖區(qū)不僅僅能夠存儲(chǔ)命令,而且可以控制消費(fèi)者WorkerThread。這就是Worker模式。下面的Sequence應(yīng)該會(huì)更加明確的描述這個(gè)模式,具體可以參看代碼。

5.         Thread-Per-Message

Thread-Per-Message模式是一個(gè)比較常用的模式了,如果我們有一個(gè)程序需要打開一個(gè)很大的文件,打開這個(gè)文件需要很長(zhǎng)的時(shí)間,那么我們就可以設(shè)計(jì)讓一個(gè)線程來一行一行的讀入文件,而不是一次性的全部打開,這樣從外部看起來就不會(huì)有停頓的感覺。這個(gè)模式Future模式一起學(xué)習(xí)。

6.         Read-Write-Lock

考慮這樣一種情況:有一個(gè)文件,有很多線程對(duì)他進(jìn)行讀寫,當(dāng)有線程在讀的時(shí)候,不允許寫,這樣是為了保證文件的一致性。當(dāng)然可以很多線程一起讀,這個(gè)沒有問題。如果有線程在寫,其他線程不允許讀寫。如果要比較好的處理這種情況,我們可以考慮使用Read-Write-Lock模式。

這個(gè)模式可以如下描述:

其實(shí)這個(gè)模式的關(guān)鍵在于鎖實(shí)現(xiàn),這里有個(gè)簡(jiǎn)單的實(shí)現(xiàn)如下:

public class Lock {

       private volatile int readingReaders = 0;

 

       @SuppressWarnings("unused")

       private volatile int writingWriters = 0;

 

       @SuppressWarnings("unused")

       private volatile int waitingWriters = 0;

 

       public synchronized void lockRead() {

 

              try {

                     while (writingWriters > 0 || waitingWriters > 0) {

                            wait();

                     }

              } catch (InterruptedException e) {

                     // null

              }

 

              readingReaders++;

       }

 

       public synchronized void unlockRead() {

              readingReaders--;

              notifyAll();

       }

 

       public synchronized void lockWrite() {

 

              waitingWriters++;

              try {

                     while (writingWriters > 0 || readingReaders > 0) {

                            wait();

                     }

              } catch (InterruptedException e) {

                     // null

              } finally {

                     waitingWriters--;

              }

 

              writingWriters++;

       }

 

       public synchronized void unlockWrite() {

              writingWriters--;

              notifyAll();

       }

}

其實(shí)在鎖里還可以添加優(yōu)先級(jí)之類的控制。

 

7.         Future

Future模式Proxy模式和Thread-Per-Message模式的結(jié)合。考慮下面的情況:

比如我們的word文檔,里頭有很多圖片在末尾,我們打開這個(gè)文檔的時(shí)候會(huì)需要同時(shí)讀取這些圖片文件,但是很明顯,如果剛剛開始就全部讀取進(jìn)來的話會(huì)消耗太多的內(nèi)存和時(shí)間,使得顯示出現(xiàn)停頓的現(xiàn)象。那么我們應(yīng)該怎么做呢,我們可以做這樣一個(gè)對(duì)象,這個(gè)對(duì)象代表需要讀入的圖片,把這個(gè)對(duì)象放在圖片的位置上,當(dāng)需要顯示這個(gè)圖片的時(shí)候,我們才真正的填充這個(gè)對(duì)象。這個(gè)就是Proxy模式了。當(dāng)然Proxy不僅僅是這么個(gè)意思,Proxy的真正意思是我們之需要訪問Proxy來操作我們真正需要操作的對(duì)象,以便實(shí)現(xiàn)對(duì)客戶段的控制。

這邊先簡(jiǎn)單描述一下Proxy模式:

當(dāng)Client請(qǐng)求的時(shí)候,我們用Proxy代替RealObject載入,當(dāng)Client真正需要getObject的時(shí)候,Proxy將調(diào)用RealObjectRealObject方法,獲得真正的RealObjct。用Sequence來描述上面這段話:

下面回到Future模式,這個(gè)模式就是我們不需要真正對(duì)象的時(shí)候,首先生成一個(gè)Proxy對(duì)象來替代,然后產(chǎn)生一個(gè)線程來讀取真正的對(duì)象,讀取結(jié)束之后將這個(gè)對(duì)象設(shè)置到Proxy中,當(dāng)真正需要這個(gè)對(duì)象的時(shí)候,我們可以從Proxy中取到。如下:

具體可以參看代碼的實(shí)現(xiàn)。

8.         Two-phase Termination

    Two-phase Termination模式就是讓線程正常結(jié)束,也就是結(jié)束之前進(jìn)行一些善后處理,釋放掉該釋放的資源,完成自己當(dāng)前的任務(wù)。在Java語言中,有一個(gè)方法stop,這個(gè)方法會(huì)使當(dāng)前線程結(jié)束,但是我們不應(yīng)該使用這個(gè)方法,因?yàn)樗麑?huì)導(dǎo)致災(zāi)難性的后果。那么我們應(yīng)該怎么做呢?這里其實(shí)上面有實(shí)現(xiàn)過,就是使用設(shè)置標(biāo)志的方法來替代stop方法。具體可以查看:已經(jīng)不贊成使用的方法和代碼。

   

 

9.         Thread-Specific Storage

    Thread-Specific Storage模式的考慮是當(dāng)資源的訪問不需要線程的通信的時(shí)候,我們可以使用這個(gè)模式,這個(gè)模式的做法是每個(gè)線程有自己的一個(gè)區(qū)域,來存儲(chǔ)自己的變量,然后需要的時(shí)候操作這個(gè)變量。在Java中,已經(jīng)實(shí)現(xiàn)了ThreadLocal,我們可以用他來實(shí)現(xiàn)這個(gè)模式,這邊有一個(gè)簡(jiǎn)單的實(shí)現(xiàn):

public class MyThreadLocal {

 

      @SuppressWarnings( { "unchecked", "unused" })

      private Map storage = Collections.synchronizedMap(new HashMap());

 

      @SuppressWarnings("unchecked")

      public Object get() {

             Thread current = Thread.currentThread();

             Object obj = storage.get(current);

             if (obj == null && !storage.containsKey(current)) {

                    obj = initValue();

                    storage.put(current, obj);

             }

 

             return obj;

      }

 

      @SuppressWarnings("unchecked")

      public void set(Object obj) {

             storage.put(Thread.currentThread(), obj);

      }

 

      public Object initValue() {

             return null;

      }

}

10.     Immutable

其實(shí)多線程的問題有一個(gè)很大的麻煩就是如何控制資源的同步,就是防止當(dāng)前線程的中間狀態(tài)被下一個(gè)線程看到,這個(gè)有兩個(gè)辦法可以實(shí)現(xiàn),首先,就是同時(shí)只能有一個(gè)線程在訪問,另外一個(gè)辦法就是使得資源變成非可變類,既然是不變的,大家就可以隨便訪問了。

11.     Balking

考慮這樣一個(gè)情況:有一個(gè)比較好的洗手的地方,你可以按按鈕來放水,其實(shí)它旁邊還有一個(gè)傳感器,可以感受到您的手過來了,應(yīng)該放水,那么如果您已經(jīng)按過按鈕,水正在放,那么傳感器的放水信號(hào)應(yīng)該如何處理呢,很顯然,需要丟棄這次放水請(qǐng)求。反過來也一樣。

Sequence如下:

 

 

線程的學(xué)習(xí)筆記和一些總結(jié)大概就這么多了,想想這段時(shí)間的學(xué)習(xí),花費(fèi)了很多的時(shí)間,但是效果是很多東西只是從書本上看來的,實(shí)在是可惜沒有辦法真正的實(shí)踐一下,所以這些東西其實(shí)應(yīng)該有更深刻的理解。希望有這么一天?。。?!

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多