簡體   English   中英

將對象添加到列表時的Java並發問題

[英]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類未呈現顯式競爭條件,但您的測試卻包含一個。 盡管getInstancegetSizedestroy方法是原子方法,但這些方法的任何組成都不是原子方法。

查看您的代碼:

@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方法)不能同時執行,但不會“排序”單個塊。

您看到的是:

  • [線程1] TestCon tst=TestCon.getInstance();
  • [線程2] tst.destroy(); //line 2 tst.destroy(); //line 2
  • [線程1] 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM