一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

java 線程安全

 Long_way 2007-07-19

java 線程安全

 

四種方式    sychronized關(guān)鍵字

  1. sychronized method(){}
  2. sychronized (objectReference) {/*block*/}
  3. static synchronized method(){}
  4. sychronized(classname.class)

其中1和2是代表鎖當(dāng)前對(duì)象,即一個(gè)對(duì)象就一個(gè)鎖,3和4代表鎖這個(gè)類,即這個(gè)類的鎖
要注意的是sychronized method()不是鎖這個(gè)函數(shù),而是鎖對(duì)象,即:如果這個(gè)類中有兩個(gè)方法都是sychronized,那么只要有兩個(gè)線程共享一個(gè)該類的reference,每個(gè)調(diào)用這兩個(gè)方法之一,不管是否同一個(gè)方法,都會(huì)用這個(gè)對(duì)象鎖進(jìn)行同步。鎖的3和4類推,即該類的不同reference調(diào)用了sychronized區(qū)段的咚咚就會(huì)受類鎖的控制

還有,如果兩個(gè)函數(shù)調(diào)用的先后順序不能被打斷,那么可以有個(gè)專門的鎖對(duì)象來完成這個(gè)任務(wù):
class MyLock
{
      synchronized getLock()
      {
          //####還沒寫完
      }
}

五個(gè)等級(jí)   參見effective java  Item 52 : Document thread safety

  1. immutable   不可變對(duì)象
  2. thread-safe 線程安全的,可以放心使用,如java.util.Timer
  3. conditionally thread-safe 條件線程安全的,如Vector和Hashtable,一般是安全的,除非存在幾個(gè)方法調(diào)用之間的順序不能被打斷,這時(shí)可以用額外的鎖來完成
  4. thread-compatible 可以使用synchronized (objectReference)來協(xié)助完成對(duì)線程的調(diào)用
  5. thread-hostile 不安全的

wait & notifyAll

 

在循環(huán)中使用wait 使用notifyAll而不是notify

pipe

 

java中也有pipe的,四個(gè)類:PipedInputStream, PipedInputReader, PipedOutputStream, PipedOutputWriter 下面是一段生產(chǎn)者消費(fèi)者的代碼(摘自core javaII):

    /* set up pipes */
    PipedOutputStream pout1 = new PipedOutputStream();
    PipedInputStream pin1 = new PipedInputStream(pout1);
    PipedOutputStream pout2 = new PipedOutputStream();
    PipedInputStream pin2 = new PipedInputStream(pout2);
    /* construct threads */
    Producer prod = new Producer(pout1);
    Filter filt = new Filter(pin1, pout2);
    Consumer cons = new Consumer(pin2);
    /* start threads */
    prod.start(); filt.start(); cons.start();

注意

 

long 和double是簡單類型中兩個(gè)特殊的咚咚:java讀他們要讀兩次,所以需要同步
死鎖是一個(gè)經(jīng)典的多線程問題,因?yàn)椴煌木€程都在等待那些根本不可能被釋放的鎖,從而導(dǎo)致所有的工作都無法完成。假設(shè)有兩個(gè)線程,分別代表兩個(gè)饑餓的人,他們必須共享刀叉并輪流吃飯。他們都需要獲得兩個(gè)鎖:共享刀和共享叉的鎖。假如線程 "A" 獲得了刀,而線程 "B" 獲得了叉。線程 A 就會(huì)進(jìn)入阻塞狀態(tài)來等待獲得叉,而線程 B 則阻塞來等待 A 所擁有的刀。這只是人為設(shè)計(jì)的例子,但盡管在運(yùn)行時(shí)很難探測(cè)到,這類情況卻時(shí)常發(fā)生。雖然要探測(cè)或推敲各種情況是非常困難的,但只要按照下面幾條規(guī)則去設(shè)計(jì)系統(tǒng),就能夠避免死鎖問題:
  • 讓所有的線程按照同樣的順序獲得一組鎖。這種方法消除了 X 和 Y 的擁有者分別等待對(duì)方的資源的問題。
  • 將多個(gè)鎖組成一組并放到同一個(gè)鎖下。前面死鎖的例子中,可以創(chuàng)建一個(gè)銀器對(duì)象的鎖。于是在獲得刀或叉之前都必須獲得這個(gè)銀器的鎖。
  • 將那些不會(huì)阻塞的可獲得資源用變量標(biāo)志出來。當(dāng)某個(gè)線程獲得銀器對(duì)象的鎖時(shí),就可以通過檢查變量來判斷是否整個(gè)銀器集合中的對(duì)象鎖都可獲得。如果是,它就可以獲得相關(guān)的鎖,否則,就要釋放掉銀器這個(gè)鎖并稍后再嘗試。
  • 最重要的是,在編寫代碼前認(rèn)真仔細(xì)地設(shè)計(jì)整個(gè)系統(tǒng)。多線程是困難的,在開始編程之前詳細(xì)設(shè)計(jì)系統(tǒng)能夠幫助你避免難以發(fā)現(xiàn)死鎖的問題。
Volatile 變量. volatile 關(guān)鍵字是 Java 語言為優(yōu)化編譯器設(shè)計(jì)的。以下面的代碼為例:
class VolatileTest { public void foo() { boolean flag = false; if(flag) { //this could happen } } }

一個(gè)優(yōu)化的編譯器可能會(huì)判斷出 if 部分的語句永遠(yuǎn)不會(huì)被執(zhí)行,就根本不會(huì)編譯這部分的代碼。如果這個(gè)類被多線程訪問, flag 被前面某個(gè)線程設(shè)置之后,在它被 if 語句測(cè)試之前,可以被其他線程重新設(shè)置。用 volatile 關(guān)鍵字來聲明變量,就可以告訴編譯器在編譯的時(shí)候,不需要通過預(yù)測(cè)變量值來優(yōu)化這部分的代碼。



無法訪問的線程 有時(shí)候雖然獲取對(duì)象鎖沒有問題,線程依然有可能進(jìn)入阻塞狀態(tài)。在 Java 編程中 IO 就是這類問題最好的例子。當(dāng)線程因?yàn)閷?duì)象內(nèi)的 IO 調(diào)用而阻塞時(shí),此對(duì)象應(yīng)當(dāng)仍能被其他線程訪問。該對(duì)象通常有責(zé)任取消這個(gè)阻塞的 IO 操作。造成阻塞調(diào)用的線程常常會(huì)令同步任務(wù)失敗。如果該對(duì)象的其他方法也是同步的,當(dāng)線程被阻塞時(shí),此對(duì)象也就相當(dāng)于被冷凍住了。其他的線程由于不能獲得對(duì)象的鎖,就不能給此對(duì)象發(fā)消息(例如,取消 IO 操作)。必須確保不在同步代碼中包含那些阻塞調(diào)用,或確認(rèn)在一個(gè)用同步阻塞代碼的對(duì)象中存在非同步方法。盡管這種方法需要花費(fèi)一些注意力來保證結(jié)果代碼安全運(yùn)行,但它允許在擁有對(duì)象的線程發(fā)生阻塞后,該對(duì)象仍能夠響應(yīng)其他線程。

調(diào)用 yield() 方法能夠?qū)?dāng)前的線程從處理器中移出到準(zhǔn)備就緒隊(duì)列中。另一個(gè)方法則是調(diào)用 sleep() 方法,使線程放棄處理器,并且在 sleep 方法中指定的時(shí)間間隔內(nèi)睡眠。

正如你所想的那樣,將這些方法隨意放在代碼的某個(gè)地方,并不能夠保證正常工作。如果線程正擁有一個(gè)鎖(因?yàn)樗谝粋€(gè)同步方法或代碼塊中),則當(dāng)它調(diào)用 yield() 時(shí)不能夠釋放這個(gè)鎖。這就意味著即使這個(gè)線程已經(jīng)被掛起,等待這個(gè)鎖釋放的其他線程依然不能繼續(xù)運(yùn)行。為了緩解這個(gè)問題,最好不在同步方法中調(diào)用 yield 方法。將那些需要同步的代碼包在一個(gè)同步塊中,里面不含有非同步的方法,并且在這些同步代碼塊之外才調(diào)用 yield。

另外一個(gè)解決方法則是調(diào)用 wait() 方法,使處理器放棄它當(dāng)前擁有的對(duì)象的鎖。如果對(duì)象在方法級(jí)別上使同步的,這種方法能夠很好的工作。因?yàn)樗鼉H僅使用了一個(gè)鎖。如果它使用 fine-grained 鎖,則 wait() 將無法放棄這些鎖。此外,一個(gè)因?yàn)檎{(diào)用 wait() 方法而阻塞的線程,只有當(dāng)其他線程調(diào)用 notifyAll() 時(shí)才會(huì)被喚醒。

在進(jìn)行多線程編程時(shí),經(jīng)常要使用同步互斥機(jī)構(gòu),但java本身沒有提供的同步互斥機(jī)構(gòu),僅提供了兩個(gè)與同步互斥有關(guān)的方法:wait()和notify(),可以用來設(shè)計(jì)信號(hào)量類:mySemaphore,它是按照Dijkstra提出的計(jì)數(shù)信號(hào)量的思想設(shè)計(jì)的。

mySemaphore有兩個(gè)最重要的成員方法:P()和V()。這兩個(gè)方法實(shí)際就實(shí)現(xiàn)了信號(hào)量的P操作和V操作。具體描述如下:

public synchronized void P(){

semaphore--;

if(semaphore<0){

try{

wait();

}catch(InterruptedException ie){}

}

}

public synchronized void V(){

semaphore++;

if(semaphore<=0)

notify();

}

其中,semaphore變量記錄了信號(hào)量的狀態(tài),wait()方法相當(dāng)于block原語,用于阻塞線程的執(zhí)行,notify()方法相當(dāng)于wakeup原語,用于喚醒線程恢復(fù)運(yùn)行。由于這兩個(gè)方法定義為synchronized,這樣java虛擬機(jī)可保證這兩個(gè)方法的原子執(zhí)行,從而實(shí)現(xiàn)了P、V操作。

二、管道

并發(fā)程序的多個(gè)線程之間的通訊通常是使用管道進(jìn)行,jdk提供了兩個(gè)管道類:PipedInpuStream和PipedOutputStream,前者用于輸入,后者用于輸出。這兩種管道應(yīng)該是能夠多次連接和關(guān)閉,在實(shí)現(xiàn)過程中,卻發(fā)現(xiàn)它們?cè)陉P(guān)閉后,不能重新建立連接。經(jīng)過仔細(xì)調(diào)試后,發(fā)現(xiàn)jdk的源代碼在處理關(guān)閉時(shí)釋放資源存在著缺陷,因此需要編寫自己的管道類:MyPipedInputStream和MyPipedOutputStream。這兩個(gè)類直接從InputStream和OutputStream繼承而來,其成員方法與實(shí)現(xiàn)基本與PipedInputStream和PipedOutputStream一致,只是在處理關(guān)閉時(shí),將類中的成員變量的值恢復(fù)成未連接時(shí)的初始值。另外,原有的管道了提供的管道容量只有1024個(gè)字節(jié),在傳輸數(shù)據(jù)量較大時(shí),可能會(huì)發(fā)生溢出,而在自己的管道類中可以任意設(shè)置管道容量,例如可以根據(jù)需要把管道容量設(shè)為64KB。以下僅給出了相應(yīng)的關(guān)閉例程:

1.MyPipedInputStream

public void close() throws IOException {

in = -1;

out = 0;

closedByReader = true;

connected = false;

closed = true;

buffer = new byte[PIPE_SIZE];

}

2.MyPipedOutputStream

public void close() throws IOException {

if (sink != null) {

sink.receivedLast();

sink.closed = true;

}

sink = null;

connected = false;

}

    本站是提供個(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)論公約

    類似文章 更多

    九九热视频经典在线观看| 亚洲中文字幕亲近伦片| 亚洲一区二区三区熟女少妇| 国产精品久久男人的天堂| 国产精品超碰在线观看| 亚洲欧洲精品一区二区三区| 国产av一区二区三区久久不卡| 少妇福利视频一区二区| 国产成人一区二区三区久久| 精品少妇一区二区三区四区| 久久综合日韩精品免费观看| 亚洲精品中文字幕一二三| 日韩1区二区三区麻豆| 熟女白浆精品一区二区| 99国产成人免费一区二区| 国产中文字幕久久黄色片| 韩国日本欧美国产三级| 中文字幕中文字幕在线十八区| 最近日韩在线免费黄片| 亚洲做性视频在线播放| 色哟哟哟在线观看视频| 日韩欧美一区二区亚洲| 欧美激情区一区二区三区| 欧美日韩综合在线第一页| 黄色片国产一区二区三区| 一区二区免费视频中文乱码国产| 在线观看视频成人午夜| 国内真实露脸偷拍视频| 日本欧美一区二区三区在线播| 亚洲一区二区三区国产| 自拍偷拍福利视频在线观看| 黄片免费播放一区二区| 久久精品少妇内射毛片| 成在线人免费视频一区二区| 亚洲一区二区三区免费的视频| 九九九热视频免费观看| 久久99青青精品免费| 日本欧美一区二区三区高清| 日本东京热视频一区二区三区| 欧美亚洲三级视频在线观看| 国产性情片一区二区三区|