【问题标题】:Why i am able to read/write arraylist at same time?为什么我能够同时读/写arraylist?
【发布时间】:2016-03-21 06:39:20
【问题描述】:

我在这里使用多个线程 .. 一个线程正在获取列表,另一个正在向列表添加名称,这两个线程都在使用共享资源,即 ArrayList object 它应该给 concurrentModification 类似的东西没有给出,或者我无法在我的代码中正确使用线程

代码如下:

import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

public class threadprac  
 {
  public static void main(String args[]){

        ArrayList<String> shared;
         shared = new ArrayList<>(); 
         String[] arr=new String[]{"amol","robin","shanu","saaru","mohit"};
         for(String n:arr)
           shared.add(n);  
         Thread tf = new Thread(new fetch(shared));
         Thread tm = new Thread(new manipulate(shared));
         tm.setName("thread-M"); tf.setName("thread-F");
         tf.start();
         tm.start();
         try {
         Thread.currentThread().sleep(2000); 
    } catch (InterruptedException ex) {
        Logger.getLogger(threadprac.class.getName()).log(Level.SEVERE, null, ex);
    }
         for(String n:shared)
           System.out.print(n+" ");  

 }    
}

class fetch implements Runnable
{
 ArrayList<String> f;
 fetch(ArrayList shared){
   this.f=shared;
   }
 @Override
 public void run(){
  displayList(); 
  }
void displayList(){
   Iterator<String> itr=f.iterator();
   while(itr.hasNext()){
      String name = itr.next();
      System.out.print(name+" ");
   }
   System.out.println();
  } 
}

class manipulate implements Runnable
{
ArrayList<String> m;
manipulate(ArrayList shared){
    this.m=shared;
}
@Override
public void run(){
    addName();
 }
void addName(){
  m.add("rohit"); 
 } 
}

【问题讨论】:

  • 从来没有说过我们不能做你正在做的事情,这样做是不安全的,并且会产生模棱两可的结果
  • @SarthakMittal .. 我正在使用一个快速失败的迭代器,并且在声明迭代器后我正在修改列表......这不应该是一个例外吗?只是好奇
  • @SarthakMittal 检查并发修改是尽最大努力执行的,如文档中所述,i。 e.有可能你不会得到异常。
  • 只是为了精确:我相信在声明迭代器之后修改列表,不足以激起ConcurrentModificationException。它通常会在列表被修改后在迭代器上调用next()hasNext() 时抛出。不过,它仍然可能发生在您的程序中。
  • 顺便说一下,在我的 Mac 上运行您的程序时,我有时会收到 ConcurrentModificationException

标签: java multithreading arraylist


【解决方案1】:

Thread.start() 需要一些时间。第一个线程很可能在第二个线程开始使用它的迭代器之前已经完成——反之亦然,无法预测哪个线程。

并发的一个问题是我们必须使用“非常可能”这样的短语,因为我们无法预测事情发生的顺序,因此某些程序的行为会变得不一致。

尝试将一些 Thread.sleep() 语句放入循环中,这样您就可以更加确定 ArrayList get()s 在 Iterator 打开时执行。

请注意,虽然添加休眠是一种快速简便的方法,可以将时间“调整”到足够长的时间段,以便您可以目睹某些情况的发生,但它们几乎不是解决实际代码中线程同步问题的正确方法。

【讨论】:

  • 我使用了一个包含 100 个名称的循环 ..它给出了相同的结果 ..即在获取时我也得到了附加值 ..所以这意味着两个线程同时运行并且没有给出任何异常跨度>
【解决方案2】:

两个线程中的每一个都只花费很少的时间(在现代 CPU 上可能不到 1 微秒),以至于它们同时执行的机会非常低。您必须在两个线程中做大量工作以确保它们同时处于活动状态。

【讨论】:

    【解决方案3】:

    正如@Slim 提到的,由于显示和添加时线程的延迟。 修改代码如下,添加 Sleep,会导致 concurrentModificationException。

    void displayList() throws InterruptedException {
            Iterator<String> itr = f.iterator();
            while (itr.hasNext()) {
                String name = itr.next();
                Thread.sleep(100);
                System.out.print(name + " ");
            }
            System.out.println();
        }
    
     ...
    
        void addName() throws InterruptedException {
        Thread.sleep(100);
        m.add("rohit");
    }
    

    例外:

    amol Exception in thread "thread-F" java.util.ConcurrentModificationException
        at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
        at java.util.ArrayList$Itr.next(ArrayList.java:851)
        at fetch.displayList(TestClass.java:43)
        at fetch.run(TestClass.java:33)
        at java.lang.Thread.run(Thread.java:745)
    

    【讨论】:

    • 投反对票的理由有哪些?我对此进行了测试,确实得到了并发修改异常。而且代码看起来也不错。
    • 看起来很奇怪,因为您已经努力强制使用ConcurrentModificationException,这与 OP 想要看到的内容有些相关,但不能。我认为这确实为帖子增加了一些价值。来自我的 +1。
    • 当然,我投了反对票。你的开场白是一个错误的限定词。此外,建议睡眠充其量也不是最好的。
    • @ChiefTwoPencils 我同意。但为了表明“异常最初没有发生是由于线程之间的时间问题”,我不得不引入一个睡眠。这只是说明线程之间的延迟可能是原因(为了理解目的),而不是需要在项目中使用的代码。
    • 时间是必要的,但不足以导致并发问题。在实际场景中,即使线程运行了更多时间,也不能保证是异常。令我困扰的是,生成一个自然显示 OP 之后的示例是微不足道的。这比提议睡觉要好得多。
    【解决方案4】:

    ArrayList 不是线程安全的。您可能应该查看类似 ConcurrentLinkedDeque

    的内容

    【讨论】:

    • 这个答案并没有真正解决问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-10
    • 1970-01-01
    • 2015-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多