版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第一文詳解Java線程中的安全策略目錄一、不可變對(duì)象二、線程封閉三、線程不安全類與寫法四、線程安全-同步容器1.ArrayList-Vector,Stack2.HashMap-HashTable(Key,Value都不能為null)3.Collections.synchronizedXXX(List、Set、Map)五、線程安全-并發(fā)容器J.U.C1.ArrayList-CopyOnWriteArrayList2.HashSet、TreeSet-CopyOnWriteArraySet、ConcurrentSkipListSet3.HashMap、TreeMap-ConcurrentHashMap、ConcurrentSkipListMap4.ConcurrentSkipListMap與ConcurrentHashMap對(duì)比如下六、安全共享對(duì)象的策略-總結(jié)
一、不可變對(duì)象
不可變對(duì)象需要滿足的條件
(1)對(duì)象創(chuàng)建以后其狀態(tài)就不能修改
(2)對(duì)象所有域都是final類型
(3)對(duì)象是正確創(chuàng)建的(在對(duì)象創(chuàng)建期間,this引用沒(méi)有溢出)
對(duì)于不可變對(duì)象,可以參見JDK中的String類
final關(guān)鍵字:類、方法、變量
(1)修飾類:該類不能被繼承,String類,基礎(chǔ)類型的包裝類(比如Integer、Long等)都是final類型。final類中的成員變量可以根據(jù)需要設(shè)置為final類型,但是final類中的所有成員方法,都會(huì)被隱式的指定為final方法。
(2)修飾方法:鎖定方法不被繼承類修改;效率。注意:一個(gè)類的private方法會(huì)被隱式的指定為final方法
(3)修飾變量:基本數(shù)據(jù)類型變量(數(shù)值被初始化后不能再修改)、引用類型變量(初始化之后則不能再指向其他的對(duì)象)
在JDK中提供了一個(gè)Collections類,這個(gè)類中提供了很多以u(píng)nmodifiable開頭的方法,如下:
Collections.unmodifiableXXX:Collection、List、Set、Map
其中Collections.unmodifiableXXX方法中的XXX可以是Collection、List、Set、Map
此時(shí),將我們自己創(chuàng)建的Collection、List、Set、Map,傳遞到Collections.unmodifiableXXX方法中,就變?yōu)椴豢勺兊牧?。此時(shí),如果修改Collection、List、Set、Map中的元素就會(huì)拋出java.lang.UnsupportedOperationException異常。
在Google的Guava中,包含了很多以Immutable開頭的類,如下:
ImmutableXXX,XXX可以是Collection、List、Set、Map
注意:使用Google的Guava,需要在Maven中添加如下依賴包:
dependency
groupIdcom.google.guava/groupId
artifactIdguava/artifactId
version23.0/version
/dependency
二、線程封閉
(1)Ad-hoc線程封閉:程序控制實(shí)現(xiàn),最糟糕,忽略
(2)堆棧封閉:局部變量,無(wú)并發(fā)問(wèn)題
(3)ThreadLocal線程封閉:特別好的封閉方法
三、線程不安全類與寫法
1.StringBuilder-StringBuffer
StringBuilder:線程不安全;
StringBuffer:線程不安全;
字符串拼接涉及到多線程操作時(shí),使用StringBuffer實(shí)現(xiàn)
在一個(gè)具體的方法中,定義一個(gè)字符串拼接對(duì)象,此時(shí)可以使用StringBuilder實(shí)現(xiàn)。因?yàn)樵谝粋€(gè)方法內(nèi)部定義局部變量進(jìn)行使用時(shí),屬于堆棧封閉,只有一個(gè)線程會(huì)使用變量,不涉及多線程對(duì)變量的操作,使用StringBuilder即可。
2.SimpleDateFormat-JodaTime
SimpleDateFormat:線程不安全,可以將其對(duì)象的實(shí)例化放入到具體的時(shí)間格式化方法中,實(shí)現(xiàn)線程安全
JodaTime:線程安全
SimpleDateFormat線程不安全的代碼示例如下:
packagemonunsafe;
importlombok.extern.slf4j.Slf4j;
importjava.text.ParseException;
importjava.text.SimpleDateFormat;
importjava.util.concurrent.CountDownLatch;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
importjava.util.concurrent.Semaphore;
@Slf4j
publicclassDateFormatExample{
privatestaticSimpleDateFormatsimpleDateFormat=newSimpleDateFormat("yyyyMMdd");
//請(qǐng)求總數(shù)
publicstaticintclientTotal=5000;
//同時(shí)并發(fā)執(zhí)行的線程數(shù)
publicstaticintthreadTotal=200;
publicstaticvoidmain(String[]args)throwsInterruptedException{
ExecutorServiceexecutorService=Executors.newCachedThreadPool();
finalSemaphoresemaphore=newSemaphore(threadTotal);
finalCountDownLatchcountDownLatch=newCountDownLatch(clientTotal);
for(inti=0;iclientTotal;i++){
executorService.execute(()-{
try{
semaphore.acquire();
update();
semaphore.release();
}catch(Exceptione){
log.error("exception",e);
countDownLatch.countDown();
countDownLatch.await();
executorService.shutdown();
publicstaticvoidupdate(){
try{
simpleDateFormat.parse("20251024");
}catch(ParseExceptione){
log.error("parseexception",e);
}
修改成如下代碼即可。
packagemonunsafe;
importlombok.extern.slf4j.Slf4j;
importjava.text.ParseException;
importjava.text.SimpleDateFormat;
importjava.util.concurrent.CountDownLatch;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
importjava.util.concurrent.Semaphore;
@Slf4j
publicclassDateFormatExample2{
//請(qǐng)求總數(shù)
publicstaticintclientTotal=5000;
//同時(shí)并發(fā)執(zhí)行的線程數(shù)
publicstaticintthreadTotal=200;
publicstaticvoidmain(String[]args)throwsInterruptedException{
ExecutorServiceexecutorService=Executors.newCachedThreadPool();
finalSemaphoresemaphore=newSemaphore(threadTotal);
finalCountDownLatchcountDownLatch=newCountDownLatch(clientTotal);
for(inti=0;iclientTotal;i++){
executorService.execute(()-{
try{
semaphore.acquire();
update();
semaphore.release();
}catch(Exceptione){
log.error("exception",e);
countDownLatch.countDown();
countDownLatch.await();
executorService.shutdown();
publicstaticvoidupdate(){
try{
SimpleDateFormatsimpleDateFormat=newSimpleDateFormat("yyyyMMdd");
simpleDateFormat.parse("20251024");
}catch(ParseExceptione){
log.error("parseexception",e);
}
對(duì)于JodaTime需要在Maven中添加如下依賴包:
dependency
groupIdjoda-time/groupId
artifactIdjoda-time/artifactId
version2.9/version
/dependency
示例代碼如下:
packagemonunsafe;
importlombok.extern.slf4j.Slf4j;
importorg.joda.time.DateTime;
importorg.joda.time.format.DateTimeFormat;
importorg.joda.time.format.DateTimeFormatter;
importjava.text.ParseException;
importjava.text.SimpleDateFormat;
importjava.util.concurrent.CountDownLatch;
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
importjava.util.concurrent.Semaphore;
@Slf4j
publicclassDateFormatExample3{
//請(qǐng)求總數(shù)
publicstaticintclientTotal=5000;
//同時(shí)并發(fā)執(zhí)行的線程數(shù)
publicstaticintthreadTotal=200;
privatestaticDateTimeFormatterdateTimeFormatter=DateTimeFormat.forPattern("yyyyMMdd");
publicstaticvoidmain(String[]args)throwsInterruptedException{
ExecutorServiceexecutorService=Executors.newCachedThreadPool();
finalSemaphoresemaphore=newSemaphore(threadTotal);
finalCountDownLatchcountDownLatch=newCountDownLatch(clientTotal);
for(inti=0;iclientTotal;i++){
finalintcount=i;
executorService.execute(()-{
try{
semaphore.acquire();
update(count);
semaphore.release();
}catch(Exceptione){
log.error("exception",e);
countDownLatch.countDown();
countDownLatch.await();
executorService.shutdown();
publicstaticvoidupdate(inti){
("{}-{}",i,DateTime.parse("20251024",dateTimeFormatter));
}
3.ArrayList、HashSet、HashMap等Collections集合類為線程不安全類
4.先檢查再執(zhí)行:if(condition(a)){handle(a);}
注意:這種寫法是線程不安全的?。。。?!
兩個(gè)線程同時(shí)執(zhí)行這種操作,同時(shí)對(duì)if條件進(jìn)行判斷,并且a變量是線程共享的,如果兩個(gè)線程均滿足if條件,則兩個(gè)線程會(huì)同時(shí)執(zhí)行handle(a)語(yǔ)句,此時(shí),handle(a)語(yǔ)句就可能不是線程安全的。
不安全的點(diǎn)在于兩個(gè)操作中,即使前面的執(zhí)行過(guò)程是線程安全的,后面的過(guò)程也是線程安全的,但是前后執(zhí)行過(guò)程的間隙不是原子性的,因此,也會(huì)引發(fā)線程不安全的問(wèn)題。
實(shí)際過(guò)程中,遇到if(condition(a)){handle(a);}類的處理時(shí),考慮a是否是線程共享的,如果是線程共享的,則需要在整個(gè)執(zhí)行方法上加鎖,或者保證if(condition(a)){handle(a);}的前后兩個(gè)操作(if判斷和代碼執(zhí)行)是原子性的。
四、線程安全-同步容器
1.ArrayList-Vector,Stack
ArrayList:線程不安全;
Vector:同步操作,但是可能會(huì)出現(xiàn)線程不安全的情況,線程不安全的代碼示例如下:
publicclassVectorExample{
privatestaticVectorIntegervector=newVector();
publicstaticvoidmain(String[]args)throwsInterruptedException{
while(true){
for(inti=0;ii++){
vector.add(i);
Threadthread1=newThread(newRunnable(){
@Override
publicvoidrun(){
for(inti=0;ivector.size();i++){
vector.remove(i);
Threadthread2=newThread(newRunnable(){
@Override
publicvoidrun(){
for(inti=0;ivector.size();i++){
vector.get(i);
thread1.start();
thread2.start();
}
Stack:繼承自Vector,先進(jìn)后出。
2.HashMap-HashTable(Key,Value都不能為null)
HashMap:線程不安全;
HashTable:線程安全,注意使用HashTable時(shí),Key,Value都不能為null;
3.Collections.synchronizedXXX(List、Set、Map)
注意:在遍歷集合的時(shí)候,不要對(duì)集合進(jìn)行更新操作。當(dāng)需要對(duì)集合中的元素進(jìn)行刪除操作時(shí),可以遍歷集合,先對(duì)需要?jiǎng)h除的元素進(jìn)行標(biāo)記,集合遍歷結(jié)束后,再進(jìn)行刪除操作。例如,下面的示例代碼:
publicclassVectorExample3{
//此方法拋出:java.util.ConcurrentModificationException
privatestaticvoidtest1(VectorIntegerv1){
for(Integeri:v1){
if(i==3){
v1.remove(i);
//此方法拋出:java.util.ConcurrentModificationException
privatestaticvoidtest2(VectorIntegerv1){
IteratorIntegeriterator=v1.iterator();
while(iterator.hasNext()){
Integeri=iterator.next();
if(i==3){
v1.remove(i);
//正常
privatestaticvoidtest3(VectorIntegerv1){
for(inti=0;iv1.size();i++){
if(i==3){
v1.remove(i);
publicstaticvoidmain(String[]args)throwsInterruptedException{
VectorIntegervector=newVector();
vector.add(1);
vector.add(2);
vector.add(3);
//test1(vector);
//test2(vector);
test3(vector);
}
五、線程安全-并發(fā)容器J.U.C
J.U.C表示的是java.util.concurrent報(bào)名的縮寫。
1.ArrayList-CopyOnWriteArrayList
ArrayList:線程不安全;
CopyOnWriteArrayList:線程安全;
寫操作時(shí)復(fù)制,當(dāng)有新元素添加到CopyOnWriteArrayList數(shù)組時(shí),先從原有的數(shù)組中拷貝一份出來(lái),然后在新的數(shù)組中進(jìn)行寫操作,寫完之后再將原來(lái)的數(shù)組指向到新的數(shù)組。整個(gè)操作都是在鎖的保護(hù)下進(jìn)行的。
CopyOnWriteArrayList缺點(diǎn):
(1)每次寫操作都需要復(fù)制一份,消耗內(nèi)存,如果元素特別多,可能導(dǎo)致GC;
(2)不能用于實(shí)時(shí)讀的場(chǎng)景,適合讀多寫少的場(chǎng)景;
CopyOnWriteArrayList設(shè)計(jì)思想:
(1)讀寫分離
(2)最終一致性
(3)使用時(shí)另外開辟空間,解決并發(fā)沖突
注意:CopyOnWriteArrayList讀操作時(shí),都是在原數(shù)組上進(jìn)行的,不需要加鎖,寫操作時(shí)復(fù)制,當(dāng)有新元素添加到CopyOnWriteArrayList數(shù)組時(shí),先從原有的集合中拷貝一份出來(lái),然后在新的數(shù)組中進(jìn)行寫操作,寫完之后再將原來(lái)的數(shù)組指向到新的數(shù)組。整個(gè)操作都是在鎖的保護(hù)下進(jìn)行的。
2.HashSet、TreeSet-CopyOnWriteArraySet、ConcurrentSkipListSet
CopyOnWriteArraySet:線程安全的,底層實(shí)現(xiàn)使用了CopyOnWriteArrayList。
ConcurrentSkipListSet:JDK6新增的類,支持排序??梢栽跇?gòu)造時(shí),自定義比較器,基于Map集合。在多線程環(huán)境下,ConcurrentSkipListSet中的contains()方法、add()、remove()、retain()等操作,都是線程安全的。但是,批量操作,比如:containsAll()、addAll()、removeAll()、retainAll()等操作,并不保證整體一定是原子操作,只能保證批量操作中的每次操作是原子性的,因?yàn)榕坎僮髦惺且匝h(huán)的形式調(diào)用的單步操作,比如removeAll()操作下以循環(huán)的方式調(diào)用remove()操作。如下代碼所示:
//ConcurrentSkipListSet類型中的removeAll()方法的源碼
publicbooleanremoveAll(Collectionc){
//OverrideAbstractSetversiontoavoidunnece
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 《GA 557.1-2005互聯(lián)網(wǎng)上網(wǎng)服務(wù)營(yíng)業(yè)場(chǎng)所信息安全管理代碼 第1部分:營(yíng)業(yè)場(chǎng)所代碼》專題研究報(bào)告
- 中學(xué)學(xué)生社團(tuán)活動(dòng)交流合作制度
- 養(yǎng)老院消防演練制度
- 企業(yè)財(cái)務(wù)分析與預(yù)算管理制度
- 2026湖北省定向清華大學(xué)選調(diào)生招錄備考題庫(kù)附答案
- 2026福建泉州市南安市衛(wèi)生事業(yè)單位赴福建醫(yī)科大學(xué)招聘編制內(nèi)衛(wèi)生類人員64人備考題庫(kù)附答案
- 2026福建省面向華東理工大學(xué)選調(diào)生選拔工作備考題庫(kù)附答案
- 2026福建福州第十九中學(xué)招聘編外行政人員(勞務(wù)派遣)1人備考題庫(kù)附答案
- 2026重慶九洲智造科技有限公司招聘研發(fā)工程師10人備考題庫(kù)附答案
- 2026遼寧大連理工大學(xué)化工學(xué)院劉家旭團(tuán)隊(duì)科研助理招聘1人(自聘)參考題庫(kù)附答案
- 初中語(yǔ)文新課程標(biāo)準(zhǔn)與解讀課件
- 無(wú)人機(jī)裝調(diào)檢修工培訓(xùn)計(jì)劃及大綱
- 中建通風(fēng)與空調(diào)施工方案
- 高考語(yǔ)言運(yùn)用題型之長(zhǎng)短句變換 學(xué)案(含答案)
- 春よ、來(lái)い(春天來(lái)了)高木綾子演奏長(zhǎng)笛曲譜鋼琴伴奏
- ARJ21機(jī)型理論知識(shí)考試題庫(kù)(匯總版)
- 2023年婁底市建設(shè)系統(tǒng)事業(yè)單位招聘考試筆試模擬試題及答案解析
- GB/T 4623-2014環(huán)形混凝土電桿
- GB/T 32065.4-2015海洋儀器環(huán)境試驗(yàn)方法第4部分:高溫試驗(yàn)
- GB/T 16823.3-2010緊固件扭矩-夾緊力試驗(yàn)
- 中介服務(wù)費(fèi)承諾書
評(píng)論
0/150
提交評(píng)論