兩個經典的執行緒安全示例分析

2021-10-11 23:33:54 字數 2977 閱讀 8608

@slf4j

(topic =

"c.case1"

)public

class

case1

public

static

void

main

(string[

] args));

list.

add(t)

; t.

start()

;}//使得每個執行緒執行結束

list.

foreach

((t)

->

catch

(interruptedexception e)})

;//統計最終結果

log.

debug

("賣出去:"

+ sellcount.

stream()

.maptoint

(a->a)

.sum()

);log.

debug

("剩餘票數:"

+ ticketwindow.

getcount()

);}}

class

ticketwindow

public

intgetcount()

public

void

setcount

(int count)

//賣出去多少張表,如果返回0則表示沒賣出去票

public

intsell

(int amount)

else

}}

尋找臨界區 :

int sell = ticketwindow.

sell

(getrandom()

);sellcount.

add(sell)

;

尋找共享變數

解決方法

可以給共享變數上鎖,使用關鍵字synchronized,可以將鎖加在sell方法上

public

synchronized

intsell

(int amount)

else

}

等價於

public

intsell

(int amount)

else

}}

@slf4j

(topic =

"c.case2"

)public

class

case2

public

static

void

main

(string[

] args)

throws interruptedexception })

; thread t2 =

newthread((

)->})

;//分別啟動t1 t2

t1.start()

; t2.

start()

;//等待t1 t2跑完

t1.join()

; t2.

join()

; log.

debug

("賬戶a :"

+ a.

getmoney()

);log.

debug

("賬戶b :"

+ b.

getmoney()

);log.

debug

("total:{}"

,(a.

getmoney()

+b.getmoney()

));}

}class

account

public

intgetmoney()

public

void

setmoney

(int money)

public

void

transfer

(account target,

int amount)

}}

臨界區

public

void

transfer

(account target,

int amount)

}}

共享變數

與上乙個例子不同的是,該臨界區存在的共享變數有兩個,分別是this.moneytarget.money,所以如果在transfer上面加上鎖,還能不能鎖得住,能 不能解決執行緒安全問題呢?

public

synchronized

void

transfer

(account target,

int amount)

}

並不能!

原因是:此時的synchronized只能鎖定住當前的物件的共享變數,也就是說誰呼叫transfer就會鎖住誰的money屬性,因此並不能解決執行緒安全問題,那麼該如果才能同時鎖住兩個物件呢?

解決方法:擴大鎖的範圍,從鎖住物件擴大至鎖住整個類,因為無論是this.moneytarget.money它們都屬於account類,因此可以修改臨界區的鎖範圍,如下:

public

void

transfer

(account target,

int amount)

}}

此時便達到我們的執行緒安全目的。

兩個lock的經典使用示例

示例一 public class numberprintdemo catch interruptedexception e 當state 1時,輪到執行緒1列印5次數字 for int j 0 j 5 j system.out.println 執行緒1列印完成後,將state賦值為2,表示接下來將輪...

兩個經典的Oracle觸發器示例

案例一 題目 觸發器 新增員工資訊,流水號作為自動編號 通過序列生成 並且判斷如果工資小於0,則改為0 如果大於10000,則改為10000。create table emp2 e id number,e no number,e name varchar2 20 e sal number selec...

兩個經典的Oracle觸發器示例

from 案例一 題目 觸發器 新增員工資訊,流水號作為自動編號 通過序列生成 並且判斷如果工資小於0,則改為0 如果大於10000,則改為10000。create table emp2 e id number,e no number,e name varchar2 20 e sal number ...