身為JAVA工作者必須了解的實戰(zhàn)知識(十一)

并發(fā)測試大致分為兩類:安全性測試(不發(fā)生任何錯誤的行為)和活躍性測試(某個良好的行為終究會發(fā)生)。

安全測試 - 通常采用測試不變性條件的形式榜贴,即判斷某個類的行為是否與其他規(guī)范保持一致豌研。

活躍性測試 - 包括進展測試和無進展測試兩個方面妹田。

性能測試與活躍性測試相關(guān),主要包括:吞吐量鹃共、響應(yīng)性鬼佣、可伸縮性。

一霜浴、正確性測試

找出需要檢查的不變條件和后延條件晶衷。

[java]view plaincopy

print?

importjava.util.concurrent.Semaphore;

publicclassBoundedBuffer?{

privatefinalSemaphore?availableItems,?availableSpaces;

privatefinalE[]?items;

privateintputPosition?=0;

privateinttakePosition?=0;

@SuppressWarnings("unchecked")

publicBoundedBuffer(intcapacity)?{

availableItems?=newSemaphore(0);

availableSpaces?=newSemaphore(capacity);

items?=?(E[])newObject[capacity];

}

publicbooleanisEmpty()?{

returnavailableItems.availablePermits()?==0;

}

publicbooleanisFull()?{

returnavailableSpaces.availablePermits()?==0;

}

publicvoidput(E?x)throwsInterruptedException?{

availableSpaces.acquire();

doInsert(x);

availableItems.release();

}

publicE?take()throwsInterruptedException?{

availableItems.acquire();

E?item?=?doExtract();

availableSpaces.release();

returnitem;

}

privatesynchronizedvoiddoInsert(E?x)?{

inti?=?putPosition;

items[i]?=?x;

putPosition?=?(++i?==?items.length)?0:?i;

}

privatesynchronizedE?doExtract()?{

inti?=?takePosition;

E?x?=?items[i];

items[i]?=null;

takePosition?=?(++i?==?items.length)?0:?i;

returnx;

}

}

1 基本的單元測試

[java]view plaincopy

print?

importstaticorg.junit.Assert.*;

importorg.junit.Test;

publicclassBoundedBufferTests?{

@Test

publicvoidtestIsEmptyWhenConstructed()?{

BoundedBuffer?bb?=newBoundedBuffer(10);

assertTrue(bb.isEmpty());

assertFalse(bb.isFull());

}

@Test

publicvoidtestIsFullAfterPuts()throwsInterruptedException?{

BoundedBuffer?bb?=newBoundedBuffer(10);

for(inti?=0;?i?<10;?i++)?{

bb.put(i);

}

assertTrue(bb.isFull());

assertTrue(bb.isEmpty());

}

}

2 對阻塞操作的測試

take方法是否阻塞、中斷處理阴孟。從空緩存中獲取一個元素晌纫。

[java]view plaincopy

print?

@Test

publicvoidtestTakeBlocksWhenEmpty(){

finalBoundedBuffer?bb?=newBoundedBuffer(10);

Thread?taker?=newThread(){

@Override

publicvoidrun()?{

try{

intunused?=??bb.take();

fail();//如果執(zhí)行到這里,那么表示出現(xiàn)了一個錯誤

}catch(InterruptedException?e)?{?}

}

};

try{

taker.start();

Thread.sleep(LOCKUP_DETECT_TIMEOUT);

taker.interrupt();

taker.join(LOCKUP_DETECT_TIMEOUT);

assertFalse(taker.isAlive());

}catch(InterruptedException?e)?{

fail();

}

}

創(chuàng)建一個“獲取”線程永丝,該線程將嘗試從空緩存中獲取一個元素锹漱。

如果take方法成功,那么表示測試失敗慕嚷。

執(zhí)行測試的線程啟動“獲取”線程哥牍,等待一段時間毕泌,然后中斷該線程。

如果“獲取”線程正確地在take方法中阻塞嗅辣,那么將拋出InterruptedException撼泛,而捕獲到這個異常的catch塊將把這個異常視為測試成功,并讓線程退出澡谭。

然后愿题,主測試線程會嘗試與“獲取”線程合并,通過調(diào)用Thread.isAlive來驗證join方法是否成功返回译暂,如果“獲取”線程可以響應(yīng)中斷抠忘,那么join能很快地完成。

使用Thread.getState來驗證線程能否在一個條件等待上阻塞外永,但這種方法并不可靠崎脉。被阻塞線程并不需要進入WAITING或者TIMED_WAITING等狀態(tài),因此JVM可以選擇通過自旋等待來實現(xiàn)阻塞伯顶。

3 安全性測試

在構(gòu)建對并發(fā)類的安全性測試中囚灼,需要解決地關(guān)鍵性問題在于,要找出那些容易檢查的屬性祭衩,這些屬性在發(fā)生錯誤的情況下極有可能失敗灶体,同時又不會使得錯誤檢查代碼人為地限制并發(fā)性。理想情況是掐暮,在測試屬性中不需要任何同步機制蝎抽。

[java]view plaincopy

print?

importjava.util.concurrent.CyclicBarrier;

importjava.util.concurrent.ExecutorService;

importjava.util.concurrent.Executors;

importjava.util.concurrent.atomic.AtomicInteger;

importjunit.framework.TestCase;

publicclassPutTakeTestextendsTestCase?{

privatestaticfinalExecutorService?pool?=?Executors.newCachedThreadPool();

privatefinalAtomicInteger?putSum?=newAtomicInteger(0);

privatefinalAtomicInteger?takeSum?=newAtomicInteger(0);

privatefinalCyclicBarrier?barrier;

privatefinalBoundedBuffer?bb;

privatefinalintnTrials,?nPairs;

publicstaticvoidmain(String[]?args)?{

newPutTakeTest(10,10,100000).test();//?示例參數(shù)

pool.shutdown();

}

staticintxorShift(inty)?{

y?^=?(y?<<6);

y?^=?(y?>>>21);

y?^=?(y?<<7);

returny;

}

publicPutTakeTest(intcapacity,intnPairs,intnTrials)?{

this.bb?=newBoundedBuffer(capacity);

this.nTrials?=?nTrials;

this.nPairs?=?nPairs;

this.barrier?=newCyclicBarrier(nPairs?*2+1);

}

voidtest()?{

try{

for(inti?=0;?i?<?nPairs;?i++)?{

pool.execute(newProducer());

pool.execute(newConsumer());

}

barrier.await();//?等待所有的線程就緒

barrier.await();//?等待所有的線程執(zhí)行完成

assertEquals(putSum.get(),?takeSum.get());

}catch(Exception?e)?{

thrownewRuntimeException(e);

}

}

classProducerimplementsRunnable?{

@Override

publicvoidrun()?{

try{

intseed?=?(this.hashCode()?^?(int)?System.nanoTime());

intsum?=0;

barrier.await();

for(inti?=?nTrials;?i?>0;?--i)?{

bb.put(seed);

sum?+=?seed;

seed?=?xorShift(seed);

}

putSum.getAndAdd(sum);

barrier.await();

}catch(Exception?e)?{

thrownewRuntimeException(e);

}

}

}

classConsumerimplementsRunnable?{

@Override

publicvoidrun()?{

try{

barrier.await();

intsum?=0;

for(inti?=?nTrials;?i?>0;?--i)?{

sum?+=?bb.take();

}

takeSum.getAndAdd(sum);

barrier.await();

}catch(Exception?e)?{

thrownewRuntimeException(e);

}

}

}

}

4 資源管理的測試

對于任何持有或管理其他對象的對象,都應(yīng)該在不需要這些對象時銷毀對他們的引用路克。測試資源泄露的例子:

[java]view plaincopy

print?

classBig?{

double[]?data?=newdouble[100000];

};

voidtestLeak()throwsInterruptedException{

BoundedBuffer?bb?=newBoundedBuffer(CAPACITY);

intheapSize1?=/*?生成堆的快照?*/;

for(inti?=0;?i?<?CAPACITY;?i++){

bb.put(newBig());

}

for(inti?=0;?i?<?CAPACITY;?i++){

bb.take();

}

intheapSize2?=/*?生成堆的快照?*/;

assertTrue(Math.abs(heapSize1?-?heapSize2)?<?THRESHOLD);

}

5 使用回調(diào)

6 產(chǎn)生更多的交替操作

二樟结、性能測試

性能測試的目標(biāo) - 根據(jù)經(jīng)驗值來調(diào)整各種不同的限值。例如:線程數(shù)量精算、緩存容量等瓢宦。

1 在PutTakeTest中增加計時功能

基于柵欄的定時器

[java]view plaincopy

print?

this.timer?=newBarrierTimer();

this.barrier?=newCyclicBarrier(nPairs?*2+1,?timer);

publicclassBarrierTimerimplementsRunnable{

privatebooleanstarted?;

privatelongstartTime?;

privatelongendTime?;

@Override

publicsynchronizedvoidrun()?{

longt?=?System.nanoTime();

if(!started?){

started?=true;

startTime?=?t;

}else{

endTime?=?t;

}

}

publicsynchronizedvoidclear(){

started?=false;

}

publicsynchronizedlonggetTime(){

returnendTime?-?startTime;

}

}

修改后的test方法中使用了基于柵欄的計時器

[java]view plaincopy

print?

voidtest(){

try{

timer.clear();

for(inti?=0;?i?<?nPairs;?i++){

pool?.execute(newProducer());

pool?.execute(newConsumer());

}

barrier?.await();

barrier?.await();

longnsPerItem?=?timer.getTime()?/?(?nPairs?*?(long)nTrials?);

System.?out?.println("Throughput:?"+?nsPerItem?+"?ns/item");

assertEquals(putSum.get(),?takeSum.get()?)

}catch(Exception?e)?{

thrownewRuntimeException(e);

}

. 生產(chǎn)者消費者模式在不同參數(shù)組合下的吞吐率

. 有界緩存在不同線程數(shù)量下的伸縮性

. 如何選擇緩存的大小

[java]view plaincopy

print?

publicstaticvoidmain(String[]?args)throwsInterruptedException?{

inttpt?=100000;//?每個線程中的測試次數(shù)

for(intcap?=1;?cap?<=?tpt;?cap?*=10){

System.?out?.println("Capacity:?"+?cap);

for(intpairs?=1;?pairs?<=128;?pairs?*=2){

TimedPutTakeTest?t?=newTimedPutTakeTest(cap,?pairs,?tpt);

System.?out?.println("Pairs:?"+?pairs?+"\t");

t.test();

System.?out?.println("\t");

Thread.?sleep(1000);

t.test();

System.?out?.println();

Thread.?sleep(1000);

}

}

pool?.shutdown();

}

查看吞吐量/線程數(shù)量的關(guān)系

2 多種算法的比較

3 響應(yīng)性衡量

三、避免性能測試的陷阱

1 垃圾回收

2 動態(tài)編譯

3 對代碼路徑的不真實采樣

4 不真實的競爭程度

5 無用代碼的消除

四灰羽、其他的測試方法

1 代碼審查

2 靜態(tài)分析工具

FindBugs驮履、Lint

3 面向方面的測試技術(shù)

4 分析與監(jiān)測工具

以上就是我推薦給Java開發(fā)者們的一面試經(jīng)典知識。但是這些知識里面并沒有太多Java全棧廉嚼、Java晉階玫镐、JAVA架構(gòu)之類的題,不是我不推薦怠噪,而是希望大家更多的從基本功做起恐似,打好基礎(chǔ),太多復(fù)雜的內(nèi)容一會兒也說不明白舰绘。

好了同學(xué)們蹂喻,我能介紹的也都全部介紹完給你們了葱椭,如果下獲得更多JAVA教學(xué)資源,可以選擇來我們這里共同交流口四,群:240448376孵运,很多大神在這里切磋學(xué)習(xí),不懂可以直接問蔓彩,晚上還有大牛免費直播教學(xué)治笨。

注:加群要求

1、具有一定工作經(jīng)驗的赤嚼,面對目前流行的技術(shù)不知從何下手旷赖,需要突破技術(shù)瓶頸的可以加,有些應(yīng)屆生和實習(xí)生也可以加更卒。

2等孵、在公司待久了,過得很安逸蹂空,但跳槽時面試碰壁俯萌。需要在短時間內(nèi)進修、跳槽拿高薪的可以加上枕。

3咐熙、如果沒有工作經(jīng)驗,但基礎(chǔ)非常扎實辨萍,對java工作機制棋恼,常用設(shè)計思想,常用java開發(fā)框架掌握熟練的锈玉,可以加爪飘。

4、覺得自己很牛B嘲玫,一般需求都能搞定悦施。但是所學(xué)的知識點沒有系統(tǒng)化并扇,很難在技術(shù)領(lǐng)域繼續(xù)突破的可以加去团。

5.阿里Java高級大牛直播講解知識點,分享知識穷蛹,多年工作經(jīng)驗的梳理和總結(jié)土陪,帶著大家全面、科學(xué)地建立自己的技術(shù)體系和技術(shù)認(rèn)知肴熏!

PS:現(xiàn)在主要講解的內(nèi)容是(反射原理鬼雀、枚舉原理與應(yīng)用注解原理蛙吏、常用設(shè)計模式源哩、正規(guī)表達式高級應(yīng)用鞋吉、JAVA操作Office原理詳解JAVA圖像處理技術(shù)励烦,等多個知識點的詳解和實戰(zhàn))

6.小號或者小白之類加群一律不給過谓着,謝謝。

最后坛掠,每一位讀到這里的網(wǎng)友赊锚,感謝你們能耐心地看完。覺得對你有幫助可以給個喜歡屉栓!希望在成為一名更優(yōu)秀的Java程序員的道路上舷蒲,我們可以一起學(xué)習(xí)、一起進步

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末友多,一起剝皮案震驚了整個濱河市牲平,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌域滥,老刑警劉巖欠拾,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異骗绕,居然都是意外死亡藐窄,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門酬土,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荆忍,“玉大人,你說我怎么就攤上這事撤缴∩餐鳎” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵屈呕,是天一觀的道長微宝。 經(jīng)常有香客問我,道長虎眨,這世上最難降的妖魔是什么蟋软? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮嗽桩,結(jié)果婚禮上岳守,老公的妹妹穿的比我還像新娘。我一直安慰自己碌冶,他們只是感情好湿痢,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著扑庞,像睡著了一般譬重。 火紅的嫁衣襯著肌膚如雪拒逮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天臀规,我揣著相機與錄音消恍,去河邊找鬼。 笑死以现,一個胖子當(dāng)著我的面吹牛狠怨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播邑遏,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼佣赖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了记盒?” 一聲冷哼從身側(cè)響起憎蛤,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎纪吮,沒想到半個月后俩檬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡碾盟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年棚辽,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冰肴。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡屈藐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出熙尉,到底是詐尸還是另有隱情联逻,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布检痰,位于F島的核電站包归,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏铅歼。R本人自食惡果不足惜公壤,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望谭贪。 院中可真熱鬧境钟,春花似錦锦担、人聲如沸俭识。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽套媚。三九已至缚态,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間堤瘤,已是汗流浹背玫芦。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留本辐,地道東北人桥帆。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像慎皱,于是被迫代替她去往敵國和親老虫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容