繁体   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