Java 即使使用同步块,ArrayList也不是线程安全的?
我尝试使用ArrayList解决生产者和消费者的问题(我知道ArrayList不是线程安全的),我确保使用Java 即使使用同步块,ArrayList也不是线程安全的?,java,multithreading,collections,Java,Multithreading,Collections,我尝试使用ArrayList解决生产者和消费者的问题(我知道ArrayList不是线程安全的),我确保使用synchronized关键字放置列表,但仍然进入ConcurrentModificationException。这就是错误所在 起始制作人请提供作业详细信息:TestJob作业 已完成:线程“使用者”中的TestJob异常 位于的java.util.ConcurrentModificationException java.util.ArrayList$Itr.checkForComodif
synchronized
关键字放置列表,但仍然进入ConcurrentModificationException
。这就是错误所在
起始制作人请提供作业详细信息:TestJob作业
已完成:线程“使用者”中的TestJob异常
位于的java.util.ConcurrentModificationException
java.util.ArrayList$Itr.checkForComodification(未知源代码)位于
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();
}
}
package test.thread;
导入java.util.List;
导入java.util.Scanner;
公共类生产者实现Runnable{
私有列表作业=null;
公共制片人(列出职位){
这个.工作=工作;
}
@凌驾
公开募捐{
System.out.println(“起始生产者”);
while(true)
{
已同步(作业){
试一试{
if(jobs.isEmpty()){
System.out.println(“请提供作业详细信息:”);
扫描仪=新的扫描仪(System.in);
字符串作业=scanner.nextLine();
jobs.add(job);
scanner.close();
jobs.notifyAll();
睡眠(4000);
}否则{
jobs.wait();
}
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
}
}
包测试线程;
导入java.util.List;
公共类使用者实现可运行{
私有列表作业=null;
公众消费者(名单){
this.jobs=列表;
}
@凌驾
公开募捐{
while(true)
{
已同步(作业){
试一试{
if(jobs.isEmpty()){
jobs.wait();
}否则{
for(字符串作业:作业){
System.out.println(“作业完成:+作业”);
删除(作业);
《睡眠》(2000年);
}
jobs.notifyAll();
}
}捕捉(中断异常e){
e、 printStackTrace();
}
}
}
}
}
包测试线程;
导入java.util.ArrayList;
导入java.util.List;
公共类测试线程{
公共静态void main(字符串…字符串)
{
列表=新的ArrayList();
生产者=新生产者(列表);
消费者=新消费者(列表);
线程prodThread=新线程(生产者,“生产者”);
线程constread=新线程(consumer,“consumer”);
prodThread.start();
constread.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);
}
Iterator it=jobs.Iterator();
while(it.hasNext()){
字符串job=it.next();
System.out.println(“作业完成:+作业”);
it.remove();
《睡眠》(2000年);
}
当然,像这样从ArrayList中删除项是非常低效的(这是
O(n^2)
),而且很容易出错,因为必须显式同步。您应该考虑使用某种类型的阻塞队列
。您得到的ConcurrentModificationException不是因为并发:您只需删除循环中的项:
for (String job : jobs) {
System.out.println("Job completed: " + job);
jobs.remove(job);
使用迭代器删除项。您的并发修改不是由线程引起的
for (String job : jobs) {
System.out.println("Job completed: " + job);
jobs.remove(job);
Thread.sleep(2000);
}
行作业。删除(作业)代码>在迭代ArrayList时修改它。迭代器仅允许在使用迭代器删除方法完成此操作时修改列表
for( Iterator<String> iter = jobs.iterator(); iter.hasNext(); )
{
String job = iter.next();
iter.remove();
}
for(迭代器iter=jobs.Iterator();iter.hasNext();)
{
字符串job=iter.next();
iter.remove();
}
尽管您得到了一个ConcurrentModificationException
但您的问题根本不是由多线程引起的
事实上,这就是问题代码:
for (String job : jobs) {
System.out.println("Job completed: " + job);
jobs.remove(job);
Thread.sleep(2000);
}
for
循环将在作业上使用迭代器
,同时您可以直接(从结构上)修改作业
(即,不通过迭代器
)。这意味着,迭代器
不再是定义良好的迭代器,它抛出此异常来告诉您
如果在迭代集合时需要从集合中删除元素,则需要使迭代器显式化:
Iterator<String> jobIterator = job.iterator();
while (jobIterator.hasNext()) {
String job = jobIterator.next();
// ... stuff ...
jobIterator.remove(); // remove the last object that was returned by next()
}
Iterator jobIterator=job.Iterator();
while(jobIterator.hasNext()){
字符串job=jobIterator.next();
//…东西。。。
jobIterator.remove();//删除next()返回的最后一个对象
}
您应该使用CopyOwWriteArrayList
以防止在使用list迭代器时出现ConcurrentModificationException
(对于代码中的每个循环,在引擎盖下使用它)无法删除元素,而请使用迭代器方法删除
Iterator<String> it = jobs.iterator();
while(it.hasNext()) {
String job = it.next();
....
it.remove();
...
}
Iterator it=jobs.Iterator();
while(it.hasNext()){
字符串job=it.next();
....
it.remove();
...
}
这将避免concurrentModificationException。必须在同一实例上同步对ArrayList的所有访问。你的代码不是这样的(例如getter和setter)。你能详细说明一下吗?@AndyTurner啊,收回了我的评论。