我希望你们都做得很好。所以提出这个问题。我有这部分代码:
private static ArrayList<String> primelist = new ArrayList<>();
static void addToList(String list_elm) {
primelist.add(list_elm);
}
基本上这个列表是由我在完整代码中创建的多个线程同时访问的(下面),这些线程负责进行一些计算并返回结果,然后将其添加到此{{1通过调用方法primelist
来调用。
但是,在所有线程都被终止后(即:完成了他们的工作),addToList(String list_elm)
中存在一些空值。因此经过一些研究后发现,ArrayList不是一个线程安全的类,因此也不是它的方法。我想问下列(也许是深层次)问题:
线程是否会在执行一行代码时被放入(等待//等待等待),也就是说它正在调用方法primelist
并且它到达了行{{1}但是在添加元素时它恰好停止了!
如果没有,请您澄清我对(特别是)ArrayList案例的困惑。 ((基本上是怎么回事?^^))
完整代码:
addToList(String list_elm)
答案 0 :(得分:1)
你正专注于错误的问题;意思是:花时间修复破碎的代码。
当您有多个线程访问相同的共享不受保护的数据时;各种各样的事情都可能发生。
另外:只是更改您正在使用的列表类型可能是不够的。你看,CopyOnWrite列表保证&#34;线程安全&#34;用于单一操作。但是当你有像
这样的东西时electron-packager
仍然不安全;即使使用CopyOnWrite列表 - 因为列表上有两个调用;并且列表可以在第一次和第二次呼叫之间改变;当其他一些线程在此期间更改列表时。
长话短说:一个解决方案是使用if (someList.size() > 1) {
do something with your list
用于 方法不并行运行的方法。
换句话说:添加您需要的保护;通过了解线程状态模型的细节而不是让自己感到困惑 - 该部分不会帮助您编写正确的代码。
鉴于你的评论:你试着在非常低的情况下解决这个问题。水平。你认为你必须了解线程状态,等待条件等等,才能找到好的&#34;解。但这不是一种有效的方法;特别是当你是新手并学习这些东西时。
首先,您应该担心采用正确解决方案。然后你可以前进并加强它;例如,通过做不同的实验。从这个意义上说,你应该理解:在真正的多线程中,我们通常会尝试从这些低级细节中抽象。相反,我们甚至会引入其他图层,例如Executors。
我想告诉你的是:查看低级细节很可能不会对你有所帮助,但此时会让你负担过重。
答案 1 :(得分:0)
竞争条件可能发生在任何地方,不仅在你编写的代码中,而且在ArrayList的实现中。
即使以最简单的形式添加到ArrayList也会涉及以下操作:
size
变量elementData[size]
size
变量当添加操作时,将大小增加到大于elementData
的长度时,也会发生调整大小:
elementData
elementData
复制到新数组elementData
elementData[size]
size
变量在您的情况下,如果您将null添加到列表中,则可能是两个线程正在尝试同时调整阵列大小。让我们说目前你的列表有10个元素。 elementData
的长度为10.因此,添加第11个值会调整elementData
elementData
复制到新阵列elementData
复制到新阵列elementData
elementData[10]
size
增加到11 elementData
elementData[11]
size
增加到12 在步骤8中发生的是线程2覆盖线程1更改的elementData
,因此elementData [10](由线程1编写)丢失。