[英]Java Concurrency Issue when add an object to a list
我有一個看起來很奇怪的問題,可能是因為我缺乏一些特定的知識。
我有一個簡單的類TestCon和一個測試類TestTest:
import java.util.*;
import java.util.concurrent.*;
public class TestCon {
private volatile static TestCon def = null;
private volatile static List<TestCon> list = Collections.synchronizedList(new ArrayList<TestCon>());
public static synchronized TestCon getInstance() {
if (def == null) {
def = new TestCon();
list.add(def);
}
return def;
}
private synchronized static TestCon addtolist(){
return new TestCon();
}
public static synchronized int getSize() {
return list.size();
}
public synchronized void destroy() {
def = null;
list.clear();
}
}
import org.testng.annotations.Test;
import org.testng.*;
public class TestTest {
@Test(threadPoolSize=50, invocationCount=15000)
public void test_getInstance() {
TestCon tst=TestCon.getInstance();
Assert.assertNotNull(tst);
Assert.assertEquals(TestCon.getSize(), 1); //line 1
tst.destroy(); //line 2
}
}
所以我的問題是為什么測試偶爾會在//line 1
失敗(列表大小為0但預期為1)。 如果我將同步添加到測試方法中-一切都很好。 如果我再次評論第2行,則測試成功。
雖然您的TestCon
類未呈現顯式競爭條件,但您的測試卻包含一個。 盡管getInstance
, getSize
和destroy
方法是原子方法,但這些方法的任何組成都不是原子方法。
查看您的代碼:
@Test(threadPoolSize = 50, invocationCount = 15000)
public void test_getInstance() {
TestCon tst = TestCon.getInstance();
Assert.assertNotNull(tst); // (1)
Assert.assertEquals(TestCon.getSize(), 1); // (2)
tst.destroy(); // (3)
}
假設您有兩個線程一起終止在第(1)行。 然后線程一成功進入第(3)行。 這意味着列表現在為空。 在該線程之后,線程2移動並檢查(2)處的列表大小,並發現列表為空:測試失敗。
synchronized
只是保護其后的代碼塊(方法主體或方法內部的語句塊)。
這意味着鎖定相同實體的其他synchronized
塊(在您的情況下為類,因為您使用的是synchronized
方法)不能同時執行,但不會“排序”單個塊。
您看到的是:
TestCon tst=TestCon.getInstance();
tst.destroy(); //line 2
tst.destroy(); //line 2
Assert.assertEquals(TestCon.getSize(), 1); //line 1
Assert.assertEquals(TestCon.getSize(), 1); //line 1
這是因為您的代碼只會創建一個所有線程都使用的TestCon
。
相反,您需要確保每個線程都有自己的TestCon
。 在ThreadLocal
查找每個線程具有不同值的字段。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.