簡體   English   中英

ArrayList即使同步塊也不安全嗎?

[英]ArrayList is not Thread safe even with synchronized block?

我正在嘗試使用ArrayList的Producer和Consumer問題(我知道Arraylist不是線程安全的),並且確保將列表與synchronized關鍵字放在一起,但仍然陷入ConcurrentModificationException 這是錯誤

開始的生產者請提供工作詳細信息:TestJob工作已完成:TestJob線程“ consumer”中的異常java.util.ArrayList $ Itr.checkForComodification中的java.util.ConcurrentModificationException(java.util.ArrayList $ Itr.next(未知)源代碼)在test.thread.Consumer.run(Consumer.java:25)在java.lang.Thread.run(未知源)

這是我的代碼:

    package test.thread;

import java.util.List;
import java.util.Scanner;

public class Producer implements Runnable {

    private List<String> jobs = null;

    public Producer(List<String> jobs) {
        this.jobs = jobs;
    }

    @Override
    public void run() {

        System.out.println("Starting Producer");
        while(true)
        {
            synchronized (jobs) {
                try {
                if (jobs.isEmpty()) {


                        System.out.println("Please provide the job details: ");
                        Scanner scanner = new Scanner(System.in);
                        String job = scanner.nextLine();
                        jobs.add(job);
                        scanner.close();
                        jobs.notifyAll();
                        Thread.sleep(4000);

                } else {
                    jobs.wait();
                }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }

    }

}


package test.thread;

import java.util.List;

public class Consumer implements Runnable {

    private List<String> jobs = null;

    public Consumer(List<String> list) {
        this.jobs = list;
    }

    @Override
    public void run() {

        while(true)
        {
            synchronized (jobs) {
                try {
                    if (jobs.isEmpty()) {

                        jobs.wait();

                    } else {
                        for (String job : jobs) {
                            System.out.println("Job completed: " + job);
                            jobs.remove(job);
                            Thread.sleep(2000);
                        }

                        jobs.notifyAll();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

        }

    }

}



package test.thread;

import java.util.ArrayList;
import java.util.List;

public class TestThread {

    public static void main(String...strings )
    {

        List<String> list = new ArrayList<String>();
        Producer producer = new Producer(list);
        Consumer consumer = new Consumer(list);
        Thread prodThread = new Thread(producer, "producer");
        Thread consThread = new Thread(consumer, "consumer");
        prodThread.start();
        consThread.start();
    }




}

您無法使用增強的for語句從要迭代的列表中刪除項目。

如果要刪除元素,則需要一個顯式的迭代器來調用remove:

Iterator<String> it = jobs.iterator();
while (it.hasNext()) {
  String job = it.next();
  System.out.println("Job completed: " + job);
  it.remove();
  Thread.sleep(2000);
}

當然,像這樣從ArrayList中刪除項目效率非常低(它是O(n^2) ),並且由於必須顯式同步,因此容易出錯。 您應該考慮改用某種BlockingQueue

盡管您收到ConcurrentModificationException您的問題根本不是多線程引起的。

實際上,這是有問題的代碼:

for (String job : jobs) {
    System.out.println("Job completed: " + job);
    jobs.remove(job);
    Thread.sleep(2000);
}

for循環將在作業上使用Iterator ,同時您直接(在結構上)修改jobs (即,不通過Iterator )。 這意味着Iterator不再是定義良好的對象,它將引發此異常以告知您。

如果在迭代集合時需要從集合中刪除元素,則需要使Iterator明確:

Iterator<String> jobIterator = job.iterator();
while (jobIterator.hasNext()) {
  String job = jobIterator.next();
  // ... stuff ...
  jobIterator.remove(); // remove the last object that was returned by next()
}

您的並發修改不是由線程引起的。

    for (String job : jobs) {
                        System.out.println("Job completed: " + job);
                        jobs.remove(job);
                        Thread.sleep(2000);
                    }

該行jobs.remove(job); 迭代時修改ArrayList。 迭代器僅在為此使用Iterators remove方法完成后才允許修改列表。

     for( Iterator<String> iter = jobs.iterator(); iter.hasNext(); )
     {
           String job = iter.next();
           iter.remove();
     } 

您不是因為並發而獲得ConcurrentModificationException:您只需在循環中刪除項目:

for (String job : jobs) {
     System.out.println("Job completed: " + job);
     jobs.remove(job);

使用迭代器刪除項目。

您應該使用CopyOwWriteArrayList來防止在使用列表Iterator發生ConcurrentModificationException (代碼中的for-each循環在CopyOwWriteArrayList使用它)

暫時無法刪除元素,請使用迭代器方法刪除。

Iterator<String> it = jobs.iterator();
while(it.hasNext()) {
      String job = it.next();
      ....
      it.remove();
      ...
}

這樣可以避免並發修改異常。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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