在Java內存模子中測試並發法式代碼。本站提示廣大學習愛好者:(在Java內存模子中測試並發法式代碼)文章只能為提供參考,不一定能成為您想要的結果。以下是在Java內存模子中測試並發法式代碼正文
讓我們來看看這段代碼:
import java.util.BitSet; import java.util.concurrent.CountDownLatch; public class AnExample { public static void main(String[] args) throws Exception { BitSet bs = new BitSet(); CountDownLatch latch = new CountDownLatch(1); Thread t1 = new Thread(new Runnable() { public void run() { try { latch.await(); Thread.sleep(1000); } catch (Exception ex) { } bs.set(1); } }); Thread t2 = new Thread(new Runnable() { public void run() { try { latch.await(); Thread.sleep(1000); } catch (Exception e) { } bs.set(2); } }); t1.start(); t2.start(); latch.countDown(); t1.join(); t2.join(); // crucial part here: System.out.println(bs.get(1)); System.out.println(bs.get(2)); } }
成績來了,這段代碼輸入的成果是甚麼呢?它畢竟能輸入甚麼成果,下面的法式即便在瓦解的JVM上,依然許可打印輸入甚麼成果呢?
讓我們來看看這個法式做了甚麼:
接上去,我們須要結構一些測試用例來檢討這些行動。明顯,個中一個只能運轉該例子,然後不雅察成果,答復下面的成績,可是,答復第二個關於許可輸入的成果,須要些技能。
游刃有余
榮幸的是,我們可使用對象。 JCStress 就是一個為懂得決這類成績而發生的測試對象。
我們可以很輕易地將我們的test case寫成JCStress可以辨認的情勢。現實上, 它曾經為我們預備好了多種能夠情形下的接口。我們須要一個例子,在這個例子中,2個線程並發地履行,履行的成果表現為2個布爾值。
我們應用一個Actor2_Arbiter1_Test<BitSet, BooleanResult2>接口, 它將為我們的2個線程供給一些辦法塊和一個轉換辦法,這個轉換辦法將表現BitSet狀況的成果轉換成一對布爾值。我們須要找個 Java 8 JVM 來運轉它, 然則如今這曾經不是甚麼成績了.
看上面的完成. 是否是特殊簡練?
public class AnExampleTest implements Actor2_Arbiter1_Test<BitSet, BooleanResult2> { @Override public void actor1(BitSet s, BooleanResult2 r) { s.set(1); } @Override public void actor2(BitSet s, BooleanResult2 r) { s.set(2); } @Override public void arbiter1(BitSet s, BooleanResult2 r) { r.r1 = s.get(1); r.r2 = s.get(2); } @Override public BitSet newState() { return new BitSet(); } @Override public BooleanResult2 newResult() { return new BooleanResult2(); } }
如今在運轉這個測試的時刻,掌握會去測驗考試各類名堂以求獲得驅動這些舉措的身分的一切能夠組合: 並行的或許非並行的, 有和無負載檢測的, 還有一行中停止很多很多次, 是以一切能夠的成果都邑被記載到.
當你想曉得你的並行代碼是若何運作的時刻,這是比靠你本身去處心積慮想出一切細節更勝一籌的方法.
另外,為了能應用到JCStress 束縛帶來的周全性的方便,我們須要給它供給一個對能夠成果的說明. 要那樣做的話我們就須要應用以下所示的一個簡略的XML文件.
<test name="org.openjdk.jcstress.tests.custom.AnExampleTest"> <contributed-by>Oleg Shelajev</contributed-by> <description> Tests if BitSet works well without synchronization. </description> <case> <match>[true, true]</match> <expect>ACCEPTABLE</expect> <description> Seeing all updates intact. </description> </case> <case> <match>[true, false]</match> <expect>ACCEPTABLE_INTERESTING</expect> <description> T2 overwrites T1 result. </description> </case> <case> <match>[false, true]</match> <expect>ACCEPTABLE_INTERESTING</expect> <description> T1 overwrites T2 result. </description> </case> <unmatched> <expect>FORBIDDEN</expect> <description> All other cases are unexpected. </description> </unmatched> </test>
如今,我們曾經預備好讓這頭野獸開端呼嘯了. 經由過程應用上面的敕令交運行測試.
java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-RestrictContended -jar tests-custom/target/jcstress.jar -t=".*AnExampleTest"
而我們所獲得的成果是一份優雅的申報.
如今很清晰的是,我們不只可以獲得預期的成果,即兩個線程都曾經設置了它們的位,也碰到了一個競爭前提,一個線程將籠罩另外一個線程的成果。
即便你看到產生了這類工作,也必定要有“隱士自有奇策”的淡定心態,不是嗎?
趁便說一下,假如你在思慮若何修正這個代碼,謎底是細心浏覽 Javadoc 中的 BitSet 類,並認識到那並不是是線程平安的,須要內部同步。這可以很輕易地經由過程增長同步塊相干設定值來完成。
synchronized (bs) { bs.set(1); }