真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

java中線程同步的代碼 java線程同步方法有哪些

java中線程同步的幾種方法

線程同步主要有以下種方法(示例中是實現(xiàn)計數(shù)的功能):

十年的恭城網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。全網(wǎng)整合營銷推廣的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整恭城建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。成都創(chuàng)新互聯(lián)從事“恭城網(wǎng)站設(shè)計”,“恭城網(wǎng)站推廣”以來,每個客戶項目都認(rèn)真落實執(zhí)行。

1、同步方法,即使用synchronized關(guān)鍵字修飾方法,例如:

public?synchronized?void?add(int?c){...}

2、同步代碼塊,即有synchronized關(guān)鍵字修飾的語句塊,例如:

public?void?addAndGet(int?c){

synchronized(this){

count?+=?c;

}

}

3、使用特殊域變量(volatile)實現(xiàn)線程同步,該方法不能保證絕對的同步。

例如:private?volatile?int?count?=?0;

4、使用鎖實現(xiàn)線程同步,例如:

private?Lock?lock?=?new?ReentrantLock();

public?void?add(int?c)?{??

lock.lock();//上鎖??

try{??

count?+=?c;??

}finally{??

lock.unlock();//解鎖??

}??

}

5、使用原子變量實現(xiàn)線程同步,在java的util.concurrent.atomic包中提供了創(chuàng)建了原子類型變量的工具類,例如:

private?AtomicInteger?count=?new?AtomicInteger(1);

public?void?add(int?c)?{

count.addAndGet(c);

}

6、使用局部變量實現(xiàn)線程同步,如果使用ThreadLocal管理變量,則每一個使用該變量的線程都獲得該變量的副本, 副本之間相互獨立,這樣每一個線程都可以隨意修改自己的變量副本,而不會對其他線程產(chǎn)生影響。

ThreadLocal 類的常用方法

new ThreadLocalT() : 創(chuàng)建一個線程本地變量

get() : 返回此線程局部變量的當(dāng)前線程副本中的值

initialValue() : 返回此線程局部變量的當(dāng)前線程的"初始值"

set(T value) : 將此線程局部變量的當(dāng)前線程副本中的值設(shè)置為value

示例代碼:

private?static?ThreadLocalInteger?count=?new?ThreadLocalInteger(){

@Override

protected?Integer?initialValue(){?

return?1;

}

};????????????

public?void?add(int?c){

count.set(count.get()?+?c);

}

7、使用阻塞隊列實現(xiàn),例如LinkedBlockingQueue,具體使用可百度LinkedBlockingQueue的用法或查看java文檔。

Java多線程初學(xué)者指南(10):使用Synchronized關(guān)鍵字同步類方法

要想解決 臟數(shù)據(jù) 的問題 最簡單的方法就是使用synchronized關(guān)鍵字來使run方法同步 代碼如下

public?synchronized?void?run(){?????}

從上面的代碼可以看出 只要在void和public之間加上synchronized關(guān)鍵字 就可以使run方法同步 也就是說 對于同一個Java類的對象實例 run方法同時只能被一個線程調(diào)用 并當(dāng)前的run執(zhí)行完后 才能被其他的線程調(diào)用 即使當(dāng)前線程執(zhí)行到了run方法中的yield方法 也只是暫停了一下 由于其他線程無法執(zhí)行run方法 因此 最終還是會由當(dāng)前的線程來繼續(xù)執(zhí)行 先看看下面的代碼

sychronized關(guān)鍵字只和一個對象實例綁定

class?Test??{????????public?synchronized?void?method()???????{???????????????????}??}?????public?class?Sync?implements?Runnable??{???????private?Test?test;???????public?void?run()?????? {????????? ? thod();?????? }???? ? public?Sync(Test?test)???? ? {???????? ? this test?=?test;?????? }?? ? ? public?static?void?main(String[]?args)?throws?Exception?? ? ? {???????? ? Test?test ?=??new?Test();??????? ?? Test?test ?=??new?Test();?????????? Sync?sync ?=?new?Sync(test );???????? ? Sync?sync ?=?new?Sync(test );???????? ? new?Thread(sync ) start();???????? ? new?Thread(sync ) start();??? ? ? }?? }

在Test類中的method方法是同步的 但上面的代碼建立了兩個Test類的實例 因此 test 和test 的method方法是分別執(zhí)行的 要想讓method同步 必須在建立Sync類的實例時向它的構(gòu)造方法中傳入同一個Test類的實例 如下面的代碼所示

Sync?sync ?=?new?Sync(test );

不僅可以使用synchronized來同步非靜態(tài)方法 也可以使用synchronized來同步靜態(tài)方法 如可以按如下方式來定義method方法

class?Test?{??? public?static?synchronized?void?method()?{???}}

建立Test類的對象實例如下

Test?test?=?new?Test();

對于靜態(tài)方法來說 只要加上了synchronized關(guān)鍵字 這個方法就是同步的 無論是使用thod() 還是使用thod()來調(diào)用method方法 method都是同步的 并不存在非靜態(tài)方法的多個實例的問題

在 種設(shè)計模式中的單件(Singleton)模式如果按傳統(tǒng)的方法設(shè)計 也是線程不安全的 下面的代碼是一個線程不安全的單件模式

package?test;//?線程安全的Singleton模式class?Singleton{????private?static?Singleton?sample;????private?Singleton()????{????}????public?static?Singleton?getInstance()????{????????if?(sample?==?null)????????{????????????Thread yield();?//?為了放大Singleton模式的線程不安全性????????????sample?=?new?Singleton();????????}????????return?sample;????}}public?class?MyThread?extends?Thread{????public?void?run()????{????????Singleton?singleton?=?Singleton getInstance();????????System out println(singleton hashCode());????}????public?static?void?main(String[]?args)????{????????Thread?threads[]?=?new?Thread[ ];????????for?(int?i?=? ;?i??threads length;?i++)????????????threads[i]?=?new?MyThread();????????for?(int?i?=? ;?i??threads length;?i++)????????????threads[i] start();????}}

在上面的代碼調(diào)用yield方法是為了使單件模式的線程不安全性表現(xiàn)出來 如果將這行去掉 上面的實現(xiàn)仍然是線程不安全的 只是出現(xiàn)的可能性小得多

程序的運行結(jié)果如下

上面的運行結(jié)果可能在不同的運行環(huán)境上有所有同 但一般這五行輸出不會完全相同 從這個輸出結(jié)果可以看出 通過getInstance方法得到的對象實例是五個 而不是我們期望的一個 這是因為當(dāng)一個線程執(zhí)行了Thread yield()后 就將CPU資源交給了另外一個線程 由于在線程之間切換時并未執(zhí)行到創(chuàng)建Singleton對象實例的語句 因此 這幾個線程都通過了if判斷 所以 就會產(chǎn)生了建立五個對象實例的情況(可能創(chuàng)建的是四個或三個對象實例 這取決于有多少個線程在創(chuàng)建Singleton對象之前通過了if判斷 每次運行時可能結(jié)果會不一樣)

要想使上面的單件模式變成線程安全的 只要為getInstance加上synchronized關(guān)鍵字即可 代碼如下

public?static?synchronized?Singleton?getInstance()?{???}

當(dāng)然 還有更簡單的方法 就是在定義Singleton變量時就建立Singleton對象 代碼如下

private?static?final?Singleton?sample?=?new?Singleton();

然后在getInstance方法中直接將sample返回即可 這種方式雖然簡單 但不知在getInstance方法中創(chuàng)建Singleton對象靈活 讀者可以根據(jù)具體的需求選擇使用不同的方法來實現(xiàn)單件模式

在使用synchronized關(guān)鍵字時有以下四點需要注意

synchronized關(guān)鍵字不能繼承

雖然可以使用synchronized來定義方法 但synchronized并不屬于方法定義的一部分 因此 synchronized關(guān)鍵字不能被繼承 如果在父類中的某個方法使用了synchronized關(guān)鍵字 而在子類中覆蓋了這個方法 在子類中的這個方法默認(rèn)情況下并不是同步的 而必須顯式地在子類的這個方法中加上synchronized關(guān)鍵字才可以 當(dāng)然 還可以在子類方法中調(diào)用父類中相應(yīng)的方法 這樣雖然子類中的方法不是同步的 但子類調(diào)用了父類的同步方法 因此 子類的方法也就相當(dāng)于同步了 這兩種方式的例子代碼如下

在子類方法中加上synchronized關(guān)鍵字

class?Parent{??? public?synchronized?void?method()?{???}}class?Child?extends?Parent{??? public?synchronized?void?method()?{???}}

在子類方法中調(diào)用父類的同步方法

class?Parent{??? public?synchronized?void?method()?{???}}class?Child?extends?Parent{????public?void?method()?{?thod();???}}

在定義接口方法時不能使用synchronized關(guān)鍵字

構(gòu)造方法不能使用synchronized關(guān)鍵字 但可以使用下節(jié)要討論的synchronized塊來進(jìn)行同步

synchronized可以自由放置

在前面的例子中使用都是將synchronized關(guān)鍵字放在方法的返回類型前面 但這并不是synchronized可放置唯一位置 在非靜態(tài)方法中 synchronized還可以放在方法定義的最前面 在靜態(tài)方法中 synchronized可以放在static的前面 代碼如下

public?synchronized?void?method();synchronized?public?void?method();public?static?synchronized?void?method();public?synchronized?static?void?method();synchronized?public?static?void?method();

但要注意 synchronized不能放在方法返回類型的后面 如下面的代碼是錯誤的

public?void?synchronized?method();public?static?void?synchronized?method();

synchronized關(guān)鍵字只能用來同步方法 不能用來同步類變量 如下面的代碼也是錯誤的

public?synchronized?int?n?=? ;public?static?synchronized?int?n?=? ;

雖然使用synchronized關(guān)鍵字同步方法是最安全的同步方式 但大量使用synchronized關(guān)鍵字會造成不必要的資源消耗以及性能損失 雖然從表面上看synchronized鎖定的是一個方法 但實際上synchronized鎖定的是一個類 也就是說 如果在非靜態(tài)方法method 和method 定義時都使用了synchronized 在method 未執(zhí)行完之前 method 是不能執(zhí)行的 靜態(tài)方法和非靜態(tài)方法的情況類似 但靜態(tài)和非靜態(tài)方法不會互相影響 看看如下的代碼

package?test;public?class?MyThread ?extends?Thread{????public?String?methodName;????public?static?void?method(String?s)????{????????System out println(s);????????while?(true)????????????;????}????public?synchronized?void?method ()????{????????method( 非靜態(tài)的method 方法 );????}????public?synchronized?void?method ()????{????????method( 非靜態(tài)的method 方法 );????}????public?static?synchronized?void?method ()????{????????method( 靜態(tài)的method 方法 );????}????public?static?synchronized?void?method ()????{????????method( 靜態(tài)的method 方法 );????}????public?void?run()????{????????try????????{????????????getClass() getMethod(methodName) invoke(this);????????}????????catch?(Exception?e)????????{????????}????}????public?static?void?main(String[]?args)?throws?Exception????{????????MyThread ?myThread ?=?new?MyThread ();????????for?(int?i?=? ;?i?=? ;?i++)????????{????????????thodName?=? method ?+?String valueOf(i);????????????new?Thread(myThread ) start();????????????sleep( );????????}????}}

運行結(jié)果如下

非靜態(tài)的method 方法靜態(tài)的method 方法

lishixinzhi/Article/program/Java/gj/201311/27526

初學(xué)Java多線程:使用Synchronized塊同步方法

synchronized關(guān)鍵字有兩種用法 第一種就是在《使用Synchronized關(guān)鍵字同步類方法》一文中所介紹的直接用在方法的定義中 另外一種就是synchronized塊 我們不僅可以通過synchronized塊來同步一個對象變量 也可以使用synchronized塊來同步類中的靜態(tài)方法和非靜態(tài)方法

synchronized塊的語法如下

public void method()

{

… …

synchronized(表達(dá)式)

{

… …

}

}

一 非靜態(tài)類方法的同步

從《使用Synchronized關(guān)鍵字同步類方法》一文中我們知道使用synchronized關(guān)鍵字來定義方法就會鎖定類中所有使用synchronzied關(guān)鍵字定義的靜態(tài)方法或非靜態(tài)方法 但這并不好理解 而如果使用synchronized塊來達(dá)到同樣的效果 就不難理解為什么會產(chǎn)生這種效果了 如果想使用synchronized塊來鎖定類中所有的同步非靜態(tài)方法 需要使用this做為synchronized塊的參數(shù)傳入synchronized塊國 代碼如下

通過synchronized塊同步非靜態(tài)方法

public class SyncBlock

{

public void method ()

{

synchronized(this)? // 相當(dāng)于對method 方法使用synchronized關(guān)鍵字

{

… …

}

}

public void method ()

{

synchronized(this)? // 相當(dāng)于對method 方法使用synchronized關(guān)鍵字

{

… …

}

}

public synchronized void method ()

{

… …

}

}

在上面的代碼中的method 和method 方法中使用了synchronized塊 而第 行的method 方法仍然使用synchronized關(guān)鍵字來定義方法 在使用同一個SyncBlock類實例時 這三個方法只要有一個正在執(zhí)行 其他兩個方法就會因未獲得同步鎖而被阻塞 在使用synchronized塊時要想達(dá)到和synchronized關(guān)鍵字同樣的效果 必須將所有的代碼都寫在synchronized塊中 否則 將無法使當(dāng)前方法中的所有代碼和其他的方法同步

除了使用this做為synchronized塊的參數(shù)外 還可以使用SyncBlock this作為synchronized塊的參數(shù)來達(dá)到同樣的效果

在內(nèi)類(InnerClass)的方法中使用synchronized塊來時 this只表示內(nèi)類 和外類(OuterClass)沒有關(guān)系 但內(nèi)類的非靜態(tài)方法可以和外類的非靜態(tài)方法同步 如在內(nèi)類InnerClass中加一個method 方法 并使method 方法和SyncBlock的三個方法同步 代碼如下

使內(nèi)類的非靜態(tài)方法和外類的非靜態(tài)方法同步

public class SyncBlock

{

… …

class InnerClass

{

public void method ()

{

synchronized(SyncBlock this)

{

… …

}

}

}

… …

}

在上面SyncBlock類的新版本中 InnerClass類的method 方法和SyncBlock類的其他三個方法同步 因此 method method method 和method 四個方法在同一時間只能有一個方法執(zhí)行

Synchronized塊不管是正常執(zhí)行完 還是因為程序出錯而異常退出synchronized塊 當(dāng)前的synchronized塊所持有的同步鎖都會自動釋放 因此 在使用synchronized塊時不必?fù)?dān)心同步鎖的釋放問題

二 靜態(tài)類方法的同步

由于在調(diào)用靜態(tài)方法時 對象實例不一定被創(chuàng)建 因此 就不能使用this來同步靜態(tài)方法 而必須使用Class對象來同步靜態(tài)方法 代碼如下

通過synchronized塊同步靜態(tài)方法

public class StaticSyncBlock

{

public static void method ()

{

synchronized(StaticSyncBlock class)

{

… …

}

}

public static synchronized void method ()

{

… …

}

}

在同步靜態(tài)方法時可以使用類的靜態(tài)字段class來得到Class對象 在上例中method 和method 方法同時只能有一個方法執(zhí)行 除了使用class字段得到Class對象外 還可以使用實例的getClass方法來得到Class對象 上例中的代碼可以修改如下

使用getClass方法得到Class對象

public class StaticSyncBlock

{

public static StaticSyncBlock instance;

public StaticSyncBlock()

{

instance = this;

}

public static void method ()

{

synchronized(instance getClass())

{

}

}

}

在上面代碼中通過一個public的靜態(tài)instance得到一個StaticSyncBlock類的實例 并通過這個實例的getClass方法得到了Class對象(一個類的所有實例通過getClass方法得到的都是同一個Class對象 因此 調(diào)用任何一個實例的getClass方法都可以) 我們還可以通過Class對象使不同類的靜態(tài)方法同步 如Test類的靜態(tài)方法method和StaticSyncBlock類的兩個靜態(tài)方法同步 代碼如下

Test類的method方法和StaticSyncBlock類的method method 方法同步

public class Test

{

public static void method()

{

synchronized(StaticSyncBlock class)

{

}

}

}

lishixinzhi/Article/program/Java/gj/201311/27374

java多線程有幾種實現(xiàn)方法?線程之間如何同步

一、為什么要線程同步

因為當(dāng)我們有多個線程要同時訪問一個變量或?qū)ο髸r,如果這些線程中既有讀又有寫操作時,就會導(dǎo)致變量值或?qū)ο蟮臓顟B(tài)出現(xiàn)混亂,從而導(dǎo)致程序異常。舉個例子,如果一個銀行賬戶同時被兩個線程操作,一個取100塊,一個存錢100塊。假設(shè)賬戶原本有0塊,如果取錢線程和存錢線程同時發(fā)生,會出現(xiàn)什么結(jié)果呢?取錢不成功,賬戶余額是100.取錢成功了,賬戶余額是0.那到底是哪個呢?很難說清楚。因此多線程同步就是要解決這個問題。

二、不同步時的代碼

Bank.Java

package?threadTest;

/**

*?@author?ww

*

*/

public?class?Bank?{

private?int?count?=0;//賬戶余額

//存錢

public??void?addMoney(int?money){

count?+=money;

System.out.println(System.currentTimeMillis()+"存進(jìn):"+money);

}

//取錢

public??void?subMoney(int?money){

if(count-money??0){

System.out.println("余額不足");

return;

}

count?-=money;

System.out.println(+System.currentTimeMillis()+"取出:"+money);

}

//查詢

public?void?lookMoney(){

System.out.println("賬戶余額:"+count);

}

}

SyncThreadTest.java

package?threadTest;

public?class?SyncThreadTest?{

public?static?void?main(String?args[]){

final?Bank?bank=new?Bank();

Thread?tadd=new?Thread(new?Runnable()?{

@Override

public?void?run()?{

//?TODO?Auto-generated?method?stub

while(true){

try?{

Thread.sleep(1000);

}?catch?(InterruptedException?e)?{

//?TODO?Auto-generated?catch?block

e.printStackTrace();

}

bank.addMoney(100);

bank.lookMoney();

System.out.println("\n");

}

}

});

Thread?tsub?=?new?Thread(new?Runnable()?{

@Override

public?void?run()?{

//?TODO?Auto-generated?method?stub

while(true){

bank.subMoney(100);

bank.lookMoney();

System.out.println("\n");

try?{

Thread.sleep(1000);

}?catch?(InterruptedException?e)?{

//?TODO?Auto-generated?catch?block

e.printStackTrace();

}

}

}

});

tsub.start();

tadd.start();

}

}

余額不足

賬戶余額:0

余額不足

賬戶余額:100

1441790503354存進(jìn):100

賬戶余額:100

1441790504354存進(jìn):100

賬戶余額:100

1441790504354取出:100

賬戶余額:100

1441790505355存進(jìn):100

賬戶余額:100

1441790505355取出:100

賬戶余額:100

三、使用同步時的代碼

(1)同步方法:

即有synchronized關(guān)鍵字修飾的方法。?由于java的每個對象都有一個內(nèi)置鎖,當(dāng)用此關(guān)鍵字修飾方法時,內(nèi)置鎖會保護(hù)整個方法。在調(diào)用該方法前,需要獲得內(nèi)置鎖,否則就處于阻塞狀態(tài)。

修改后的Bank.java

package?threadTest;

/**

*?@author?ww

*

*/

public?class?Bank?{

private?int?count?=0;//賬戶余額

//存錢

public??synchronized?void?addMoney(int?money){

count?+=money;

System.out.println(System.currentTimeMillis()+"存進(jìn):"+money);

}

//取錢

public??synchronized?void?subMoney(int?money){

if(count-money??0){

System.out.println("余額不足");

return;

}

count?-=money;

System.out.println(+System.currentTimeMillis()+"取出:"+money);

}

//查詢

public?void?lookMoney(){

System.out.println("賬戶余額:"+count);

}

}

再看看運行結(jié)果:

余額不足

賬戶余額:0

余額不足

賬戶余額:0

1441790837380存進(jìn):100

賬戶余額:100

1441790838380取出:100

賬戶余額:0

1441790838380存進(jìn):100

賬戶余額:100

1441790839381取出:100

賬戶余額:0

瞬間感覺可以理解了吧。

注: synchronized關(guān)鍵字也可以修飾靜態(tài)方法,此時如果調(diào)用該靜態(tài)方法,將會鎖住整個類

(2)同步代碼塊

即有synchronized關(guān)鍵字修飾的語句塊。被該關(guān)鍵字修飾的語句塊會自動被加上內(nèi)置鎖,從而實現(xiàn)同步

Bank.java代碼如下:

package?threadTest;

/**

*?@author?ww

*

*/

public?class?Bank?{

private?int?count?=0;//賬戶余額

//存錢

public???void?addMoney(int?money){

synchronized?(this)?{

count?+=money;

}

System.out.println(System.currentTimeMillis()+"存進(jìn):"+money);

}

//取錢

public???void?subMoney(int?money){

synchronized?(this)?{

if(count-money??0){

System.out.println("余額不足");

return;

}

count?-=money;

}

System.out.println(+System.currentTimeMillis()+"取出:"+money);

}

//查詢

public?void?lookMoney(){

System.out.println("賬戶余額:"+count);

}

}

運行結(jié)果如下:

余額不足??

賬戶余額:0??

1441791806699存進(jìn):100??

賬戶余額:100??

1441791806700取出:100??

賬戶余額:0??

1441791807699存進(jìn):100??

賬戶余額:100

效果和方法一差不多。

注:同步是一種高開銷的操作,因此應(yīng)該盡量減少同步的內(nèi)容。通常沒有必要同步整個方法,使用synchronized代碼塊同步關(guān)鍵代碼即可。

(3)使用特殊域變量(volatile)實現(xiàn)線程同步

a.volatile關(guān)鍵字為域變量的訪問提供了一種免鎖機(jī)制

b.使用volatile修飾域相當(dāng)于告訴虛擬機(jī)該域可能會被其他線程更新

c.因此每次使用該域就要重新計算,而不是使用寄存器中的值

d.volatile不會提供任何原子操作,它也不能用來修飾final類型的變量

Bank.java代碼如下:

package?threadTest;

/**

*?@author?ww

*

*/

public?class?Bank?{

private?volatile?int?count?=?0;//?賬戶余額

//?存錢

public?void?addMoney(int?money)?{

count?+=?money;

System.out.println(System.currentTimeMillis()?+?"存進(jìn):"?+?money);

}

//?取錢

public?void?subMoney(int?money)?{

if?(count?-?money??0)?{

System.out.println("余額不足");

return;

}

count?-=?money;

System.out.println(+System.currentTimeMillis()?+?"取出:"?+?money);

}

//?查詢

public?void?lookMoney()?{

System.out.println("賬戶余額:"?+?count);

}

}

運行效果怎樣呢?

余額不足

賬戶余額:0

余額不足

賬戶余額:100

1441792010959存進(jìn):100

賬戶余額:100

1441792011960取出:100

賬戶余額:0

1441792011961存進(jìn):100

賬戶余額:100

是不是又看不懂了,又亂了。這是為什么呢?就是因為volatile不能保證原子操作導(dǎo)致的,因此volatile不能代替synchronized。此外volatile會組織編譯器對代碼優(yōu)化,因此能不使用它就不適用它吧。它的原理是每次要線程要訪問volatile修飾的變量時都是從內(nèi)存中讀取,而不是存緩存當(dāng)中讀取,因此每個線程訪問到的變量值都是一樣的。這樣就保證了同步。

(4)使用重入鎖實現(xiàn)線程同步

在JavaSE5.0中新增了一個java.util.concurrent包來支持同步。ReentrantLock類是可重入、互斥、實現(xiàn)了Lock接口的鎖,?它與使用synchronized方法和快具有相同的基本行為和語義,并且擴(kuò)展了其能力。

ReenreantLock類的常用方法有:

ReentrantLock() : 創(chuàng)建一個ReentrantLock實例

lock() : 獲得鎖

unlock() : 釋放鎖

注:ReentrantLock()還有一個可以創(chuàng)建公平鎖的構(gòu)造方法,但由于能大幅度降低程序運行效率,不推薦使用?

Bank.java代碼修改如下:

package?threadTest;

import?java.util.concurrent.locks.Lock;

import?java.util.concurrent.locks.ReentrantLock;

/**

*?@author?ww

*

*/

public?class?Bank?{

private??int?count?=?0;//?賬戶余額

//需要聲明這個鎖

private?Lock?lock?=?new?ReentrantLock();

//?存錢

public?void?addMoney(int?money)?{

lock.lock();//上鎖

try{

count?+=?money;

System.out.println(System.currentTimeMillis()?+?"存進(jìn):"?+?money);

}finally{

lock.unlock();//解鎖

}

}

//?取錢

public?void?subMoney(int?money)?{

lock.lock();

try{

if?(count?-?money??0)?{

System.out.println("余額不足");

return;

}

count?-=?money;

System.out.println(+System.currentTimeMillis()?+?"取出:"?+?money);

}finally{

lock.unlock();

}

}

//?查詢

public?void?lookMoney()?{

System.out.println("賬戶余額:"?+?count);

}

}

運行效果怎么樣呢?

余額不足

賬戶余額:0

余額不足

賬戶余額:0

1441792891934存進(jìn):100

賬戶余額:100

1441792892935存進(jìn):100

賬戶余額:200

1441792892954取出:100

賬戶余額:100

效果和前兩種方法差不多。

如果synchronized關(guān)鍵字能滿足用戶的需求,就用synchronized,因為它能簡化代碼 。如果需要更高級的功能,就用ReentrantLock類,此時要注意及時釋放鎖,否則會出現(xiàn)死鎖,通常在finally代碼釋放鎖?

(5)使用局部變量實現(xiàn)線程同步

Bank.java代碼如下:

package?threadTest;

/**

*?@author?ww

*

*/

public?class?Bank?{

private?static?ThreadLocalInteger?count?=?new?ThreadLocalInteger(){

@Override

protected?Integer?initialValue()?{

//?TODO?Auto-generated?method?stub

return?0;

}

};

//?存錢

public?void?addMoney(int?money)?{

count.set(count.get()+money);

System.out.println(System.currentTimeMillis()?+?"存進(jìn):"?+?money);

}

//?取錢

public?void?subMoney(int?money)?{

if?(count.get()?-?money??0)?{

System.out.println("余額不足");

return;

}

count.set(count.get()-?money);

System.out.println(+System.currentTimeMillis()?+?"取出:"?+?money);

}

//?查詢

public?void?lookMoney()?{

System.out.println("賬戶余額:"?+?count.get());

}

}

運行效果:

余額不足

賬戶余額:0

余額不足

賬戶余額:0

1441794247939存進(jìn):100

賬戶余額:100

余額不足

1441794248940存進(jìn):100

賬戶余額:0

賬戶余額:200

余額不足

賬戶余額:0

1441794249941存進(jìn):100

賬戶余額:300

看了運行效果,一開始一頭霧水,怎么只讓存,不讓取?。靠纯碩hreadLocal的原理:

如果使用ThreadLocal管理變量,則每一個使用該變量的線程都獲得該變量的副本,副本之間相互獨立,這樣每一個線程都可以隨意修改自己的變量副本,而不會對其他線程產(chǎn)生影響。現(xiàn)在明白了吧,原來每個線程運行的都是一個副本,也就是說存錢和取錢是兩個賬戶,知識名字相同而已。所以就會發(fā)生上面的效果。

ThreadLocal與同步機(jī)制?

a.ThreadLocal與同步機(jī)制都是為了解決多線程中相同變量的訪問沖突問題

b.前者采用以"空間換時間"的方法,后者采用以"時間換空間"的方式


當(dāng)前標(biāo)題:java中線程同步的代碼 java線程同步方法有哪些
轉(zhuǎn)載來源:http://weahome.cn/article/ddghjhh.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部