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

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

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

活躍性測試 - 包括進(jìn)展測試和無進(jìn)展測試兩個方面。

性能測試與活躍性測試相關(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來驗證線程能否在一個條件等待上阻塞,但這種方法并不可靠。被阻塞線程并不需要進(jìn)入WAITING或者TIMED_WAITING等狀態(tài),因此JVM可以選擇通過自旋等待來實現(xiàn)阻塞。

3 安全性測試

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

[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)者消費(fèi)者模式在不同參數(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í),不懂可以直接問,晚上還有大牛免費(fèi)直播教學(xué)。

注:加群要求

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

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

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

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

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

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

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容