[英]Is externally synchronized ArrayList thread safe if its fields are not volatile?
[英]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.