如何设计java线程安全类_如何设计线程安全的Java程序
什么是線程安全的(thread-safe)?
在java中,線程安全的指的是代碼可以在并發(fā)的或者多線程的環(huán)境下安全的使用或者共享,并且它們都將按照期望的方式運行。任何代碼,類或者對象,如果它們在并發(fā)的環(huán)境中運行表現(xiàn)出的行為與在非并發(fā)環(huán)境下表現(xiàn)出的行為不一致,那么它們就不能被稱為線程安全的。
本片文章不會非常仔細(xì)的介紹線程安全或者Java中的異步處理,我們將通過幾個例子來幫助你理解什么是線程安全的然后告訴你如何讓你的代碼線程安全。
一個non-thread-safe的例子
public class Counter {
private int count;
/*
* 這個方法不是線程安全的,因為++操作不是原子操作
*/
public int getCount(){
return count++;
}
} 上面的例子不是線程安全的,因為++(自增操作)不是一個原子操作(atomic operation),而是會被拆分成讀、更新和寫操作(read,update,write)三部分,如果多個線程大約在同一時刻調(diào)用getCount()方法,這三個操作可能會互相重合(coincide)或者重疊(overlap),比如:當(dāng)thread1正在更新數(shù)據(jù),thread2此時讀取數(shù)據(jù),那他將會獲得原來的舊數(shù)據(jù),最后的結(jié)果就是thread2會覆蓋掉thread1對數(shù)據(jù)的增加操作,結(jié)果就是:一個數(shù)據(jù)被丟失了,就是因為程序是并發(fā)調(diào)用的。
如何在Java中實現(xiàn)線程安全?
要使上面的方法線程安全,可以有很多種方式:
1)使用synchronized關(guān)鍵字來鎖定getCount方法,以保證同一時刻只有一個線程可以訪問getCount方法,這樣做就能避免重合(coincide)或者重疊(overlap)問題。
2)使用AutomicInteger,這樣就將++變成了原子操作,因為原子操作是線程安全的,這樣做還節(jié)省了額外的同步操作的開銷。
下面是一個實現(xiàn)線程安全的例子:
public class Counter {
private int count;
AtomicInteger atomicCount = new AtomicInteger( 0 );
/*
* 現(xiàn)在這個方法是線程安全的,因為增加了synchronized
*/
public synchronized int getCount(){
return count++;
}
/*
*這個方法是線程安全的,因為count的增加操作是原子操作
*/
public int getCountAtomically(){
return atomicCount.incrementAndGet();
}
} 關(guān)于Thread-Safe的一些重要的點:
這些點在你寫線程安全的程序的時候是很有用的,而且也能幫你避免一些很嚴(yán)重的并發(fā)問題,比如:競爭條件(race condition)或者死鎖
1)不可變的對象(immutable objects)默認(rèn)就是線程安全的,因為它們的狀態(tài)一旦創(chuàng)建就不能被改變。由于字符串在Java中就是不可變的,所以它們原本就是線程安全的(關(guān)于不可變對象,后期會有相關(guān)文章進(jìn)行說明)。
2)只讀的或者被final修飾的變量也是線程安全的。
3)鎖機(jī)制在Java中是一種實現(xiàn)線程安全的方式。
4)靜態(tài)變量如果沒有被正確的synchronized,那么它將成為線程安全問題的主要原因。
5)Java中的一些線程安全的例子:Vector, Hashtable, ConcurrentHashMap, String等。
6)Java中的原子操作是線程安全的,比如從內(nèi)存中讀取一個32位的int值是線程安全的,因為它是原子操作,所以不會與其他線程交錯。
7)局部變量也是線程安全的,因為每一個線程都會有屬于她自己的一份拷貝。使用局部變量是一種很好的實現(xiàn)線程安全的方式。
8)為了實現(xiàn)線程安全,盡可能地減少多個線程中對象的共享。
9)volatile關(guān)鍵字可以用來指示線程不緩存該變量而是直接從主內(nèi)存中讀取,也可以指示JVM不從多線程的角度來重新排序或者優(yōu)化代碼(not to reorder or optimize code from threading perspective)。
以上就是本文介紹的一些內(nèi)容。
線程安全是一個比較難以掌握的概念,為了確定程序是否線程安全你需要考慮多并發(fā)的情況,另外JVM為了會對代碼進(jìn)行優(yōu)化,而優(yōu)化的過程就會涉及到對代碼的重新排序,所以看起來是串行的程序在開發(fā)環(huán)境中運行良好,但并不能保證在生產(chǎn)環(huán)境中會同樣良好,因為JVM會盡最大可能的進(jìn)行調(diào)整,從而進(jìn)行一些代碼重排序和優(yōu)化,這樣就會導(dǎo)致線程安全的問題。
----------------------------------------------------------------
小人不才,如有問題,歡迎各位不吝賜教!
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的如何设计java线程安全类_如何设计线程安全的Java程序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 站长平台怎么添加网站(站长平台怎么添加网
- 下一篇: java把控件跑挂了_Java代码动态修