Java 为什么未同步的ArrayList对象添加方法行为不正常

Java 为什么未同步的ArrayList对象添加方法行为不正常,java,multithreading,arraylist,add,Java,Multithreading,Arraylist,Add,下面是示例代码 1) ArrayList是传递给ThreadPool的每个线程的单个对象 2) 在执行结束时,列表大小应为50,如果检查样本输出,则其可能不是50。有时它可能是41或47这样,为什么它会这样 public class Test { ArrayList list=new ArrayList(); public static void main(String[] args) { ExecutorService executorService3 = E

下面是示例代码

1) ArrayList是传递给ThreadPool的每个线程的单个对象

2) 在执行结束时,列表大小应为50,如果检查样本输出,则其可能不是50。有时它可能是41或47这样,为什么它会这样

public class Test {

    ArrayList list=new ArrayList();
    public static void main(String[] args) {
        ExecutorService executorService3 = Executors.newScheduledThreadPool(10);
        Test test=new Test();
        for(int i=0;i<5;i++)
        {
            Mythread t1=new Mythread(test.list);

            executorService3.execute(t1);
        }

        executorService3.shutdown();

        while(executorService3.isShutdown())
        {
            //---This is not giveging proper output as expected is 50.--
            System.out.println("List size="+test.list.size());
            break;
        }
    }
}


class Mythread implements Runnable {

    List list=null;
    Mythread(List list) {
        this.list=list;
    }

    @Override
    public void run() {
        for(int i=0;i<10;i++) {
            this.list.add(i);   
        }
    }
}
公共类测试{
ArrayList=新建ArrayList();
公共静态void main(字符串[]args){
ExecutorService executorService3=Executors.newScheduledThreadPool(10);
测试=新测试();

对于(inti=0;i,这是一个并发问题。 在我看来,你有: 将在同一对象上执行run方法的5个线程。多个线程可以在数组列表中的同一位置插入变量,因为它不同步。
您可以打印列表的内容吗?

您的代码没有等待线程完成执行

System.out.println("List size="+test.list.size());
不能保证它们已经完成,因此也不能保证列表包含预期的50项。请使用waittermination方法(),例如:

(为简洁起见,省略了异常处理)

如中所述:

请注意,此实现未同步。如果多个线程同时访问ArrayList实例,并且至少有一个线程在结构上修改了列表,则必须在外部对其进行同步

因此,它“表现不正常”,因为您没有按照文档中的描述使用它

正如Javadoc中所建议的,您可以将
列表
包装在一个同步列表中:

List<Integer> list = Collections.synchronizedList(new ArrayList<>());
List List=Collections.synchronizedList(新的ArrayList());

Hi Bob感谢您的回复,我认为您错了,“多线程可以增加i变量”--这里i variabe是Mythread类的run()方法内部,Mythread对象创建是循环的主方法内部。我也有同样的感觉,但如果您在查看我的代码时(executorService3.IsShutton())//当它关闭时返回true对吗?{}Hi Gothytim,我已经尝试过executorService3.WaitTermination(1,TimeUnit.SECONDS);通过增加等待时间,但仍然获得相同的意外数组大小。您的
Mythread
类不是线程。看到“线程”会让人困惑您提交给
ExecutorService
的东西的通用名称是“task”。
MyTask
对于类来说是一个更好的名称。问:在
main()
例程中
while
循环应该完成什么?
executorService3.isShutdown()
将在第一次和每次调用时返回
true
,因为您的主线程在上面一行关闭了服务。也许您应该使用
executorService3.awaitTermination()
。问:您的意思是写“异步”吗在您的问题标题中?或者这是一个输入错误?您的线程在访问
列表时肯定不使用同步,但“异步”是一种非常规的编写方式。大多数人会说“未同步”或“未同步”。区别是“异步”听起来好像是您主动删除了同步,而“unsynchronized”则更被动(即您忽略了它。)Re“在执行结束时,列表大小应为50”事实上,由于您的代码允许多个线程在不同步的情况下更新列表,因此您不应该期望出现这种结果。如果您将代码更改为在检查列表长度之前等待所有任务终止,则可能会出现这种结果,但不能保证会出现这种结果。此程序应该让邪恶的事情发生,因为这是在没有任何同步的情况下修改列表。你应该认为结果会很糟糕。我喜欢这个答案thaks Andy Turner。结论是:--当两个或更多线程尝试同时修改列表结构时,列表应该是“同步的”这正是文档中引用的内容,所以,是的。除了它是“至少一个”,而不是“2个或更多”这一事实之外。阅读引用。它都在里面。“至少一个”是一个数学术语,表示一个或多个。语句是“至少一个线程修改”.我的问题是,在一个线程的情况下,需要什么样的同步。我明白了,这不是“至少一个线程修改”,而是“至少一个线程修改”
List<Integer> list = Collections.synchronizedList(new ArrayList<>());