当一个线程在激活时不处于(Runnable)状态时

时间:2017-03-20 13:26:11

标签: arraylist thread-safety copyonwritearraylist

我希望你们都做得很好。所以提出这个问题。我有这部分代码:

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)

2 个答案:

答案 0 :(得分:1)

你正专注于错误的问题;意思是:花时间修复破碎的代码。

当您有多个线程访问相同的共享不受保护的数据时;各种各样的事情都可能发生。

另外:只是更改您正在使用的列表类型可能是不够的。你看,CopyOnWrite列表保证&#34;线程安全&#34;用于单一操作。但是当你有像

这样的东西时
electron-packager

仍然不安全;即使使用CopyOnWrite列表 - 因为列表上有两个调用;并且列表可以在第一次和第二次呼叫之间改变;当其他一些线程在此期间更改列表时。

长话短说:一个解决方案是使用if (someList.size() > 1) { do something with your list 用于 方法并行运行的方法。

换句话说:添加您需要的保护;通过了解线程状态模型的细节而不是让自己感到困惑 - 该部分不会帮助您编写正确的代码。

鉴于你的评论:你试着在非常低的情况下解决这个问题。水平。你认为你必须了解线程状态,等待条件等等,才能找到好的&#34;解。但这不是一种有效的方法;特别是当你是新手并学习这些东西时。

首先,您应该担心采用正确解决方案。然后你可以前进并加强它;例如,通过做不同的实验。从这个意义上说,你应该理解:在真正的多线程中,我们通常会尝试从这些低级细节中抽象。相反,我们甚至会引入其他图层,例如Executors

我想告诉你的是:查看低级细节很可能不会对你有所帮助,但此时会让你负担过重。

答案 1 :(得分:0)

竞争条件可能发生在任何地方,不仅在你编写的代码中,而且在ArrayList的实现中。

即使以最简单的形式添加到ArrayList也会涉及以下操作:

  1. 阅读size变量
  2. 将数据写入elementData[size]
  3. 增加size变量
  4. 当添加操作时,将大小增加到大于elementData的长度时,也会发生调整大小:

    1. 制作一个比当前elementData
    2. 大1.5倍的新数组
    3. 将值从elementData复制到新数组
    4. 将新数组分配给elementData
    5. 将数据写入elementData[size]
    6. 增加size变量
    7. 在您的情况下,如果您将null添加到列表中,则可能是两个线程正在尝试同时调整阵列大小。让我们说目前你的列表有10个元素。 elementData的长度为10.因此,添加第11个值会调整elementData

      的大小
      1. 线程1创建一个长度为15的新数组X
      2. 线程1将数据从elementData复制到新阵列
      3. 线程2创建一个长度为15的新数组Y
      4. 线程2将数据从elementData复制到新阵列
      5. 主题1将X分配给elementData
      6. 线程1将值写入elementData[10]
      7. 主题1将size增加到11
      8. 主题2将Y分配给elementData
      9. 线程2将值写入elementData[11]
      10. 主题2将size增加到12
      11. elementData [10]作为结果将为null
      12. 在步骤8中发生的是线程2覆盖线程1更改的elementData,因此elementData [10](由线程1编写)丢失。