Java 为什么不同步会使ArrayList更快、更不安全?

Java 为什么不同步会使ArrayList更快、更不安全?,java,concurrency,arraylist,Java,Concurrency,Arraylist,我宣读了以下声明: ArrayList是不同步的,因此比Vector更快,但在多线程环境中不太安全 我想知道为什么不同步可以提高速度,为什么不那么安全?由于这一事实,非阻塞数据结构将比bock的数据结构更快。对于阻塞数据结构,如果某个实体获取了某个资源,那么一旦该资源可用,另一个实体将需要时间来获取该资源 但是,在某些情况下,这可能会因情况而异。争用的要点是在写入期间。如果可以保证数据结构中包含的数据不会发生更改,则已添加该数据,并且仅访问该数据以读取该值,则不会出现问题。当写入和读取、写入和写

我宣读了以下声明:

ArrayList是不同步的,因此比Vector更快,但在多线程环境中不太安全


我想知道为什么不同步可以提高速度,为什么不那么安全?

由于这一事实,非阻塞数据结构将比bock的数据结构更快。对于阻塞数据结构,如果某个实体获取了某个资源,那么一旦该资源可用,另一个实体将需要时间来获取该资源


但是,在某些情况下,这可能会因情况而异。争用的要点是在写入期间。如果可以保证数据结构中包含的数据不会发生更改,则已添加该数据,并且仅访问该数据以读取该值,则不会出现问题。当写入和读取、写入和写入之间存在冲突时,就会出现问题

同步的关键在于,它意味着在任何给定时间只有一个线程可以访问对象。以一盒巧克力为例。如果盒子是同步的(向量),你先到达那里,没有人可以拿走任何东西,你就可以得到你的选择。如果盒子没有同步(ArrayList),任何路过的人都可以抓到一块巧克力——它会很快消失,但你可能得不到你想要的巧克力。

我将尝试解决你的两个问题:

提速

如果
ArrayList
被同步,并且多个线程试图同时从列表中读取数据,那么线程将不得不等待获取列表上的独占锁。通过使列表保持不同步,线程不必等待,程序将运行得更快

不安全


如果多个线程同时读取和写入列表,则线程的列表视图可能不稳定,这可能会导致多线程程序不稳定。

同步的数据结构使用锁(或其他同步结构)确保其数据始终处于一致状态。通常,这需要一个或多个线程等待另一个线程完成结构状态的更新,这将降低性能,因为在以前没有的地方引入了等待。

2个线程可以同时修改列表,并在列表中添加新项目或删除/修改相同项目,因为不存在同步(或锁定机制,如果愿意)。因此,假设您在其他人尝试处理列表中的一个项目时删除了该项目,或者您在其他人使用该项目时修改了该项目,这不是很安全


阅读“注意这个实现是不同步的。”一段,它解释得更好一些

我忘了,考虑到速度,想象一下,当你试图控制对数据的访问时,你添加了一些机制来阻止其他人访问你的数据,这似乎很简单。因此,您添加了更多的计算,因此速度较慢

ArrayList未同步且 因此比矢量更快,但更少 在多线程环境中安全

我想知道为什么 不同步可以提高性能 速度,以及为什么它会不那么安全

当多个线程读取/写入共享内存位置时,由于缺乏互斥性和适当的可见性,程序可能会计算不正确的结果。因此,缺乏同步被认为是“不安全的”。杰里米·曼森(Jeremy Manson)的这本书也许能很好地介绍这个话题

当JVM执行同步方法时,它会确保当前线程在调用该方法的对象上具有独占锁。类似地,当方法完成执行时,JVM释放执行线程持有的锁。同步方法提供互斥和可见性保证,对于执行代码的“安全”(即保证正确性)非常重要。但是,如果只有一个线程访问对象的方法,就不需要担心安全问题。尽管JVM性能多年来有所提高,但无争用同步(即仅一个线程访问的对象的锁定/解锁)仍然需要非零的时间。对于不同步的方法,JVM不需要支付额外的代价——因此它们比同步的方法更快

Vector
s将他们的选择强加给你。所有方法都是同步的,很难错误地使用它们。但是当在单线程上下文中使用
Vector
s时,您将为不必要的额外同步付出代价<代码>数组列表s将选择权留给您。在多线程上下文中使用时,由您(程序员)正确同步代码;但是,当在单线程上下文中使用时,可以保证不会支付任何额外的同步开销

此外,当最初填充集合并随后读取时,
ArrayList
s即使在多线程上下文中也会表现得更好。例如,考虑这种方法:

public synchronized List<String> getList() {
    List<String> list = new Vector<String>();
    list.add("Foo");
    list.add("Bar");
    return Collections.unmodifiableList(list);
}
公共同步列表getList(){
列表=新向量();
列表。添加(“Foo”);
列表。添加(“酒吧”);
返回集合。不可修改列表(列表);
}

创建、填充列表,并安全发布列表的不可变视图。查看上面的代码,很明显,该列表的所有后续使用都是读取的,即使被多个线程使用,也不需要任何同步-该对象实际上是不可变的。在这里使用
向量
会导致同步开销,即使在不需要同步的读取中也是如此;使用
ArrayList
会更好。

@Lukas,这些问题在语义上是不同的。嗯,是的,你是对的,因为“安全性”@Lukas,是的。这就是我所说的。同步没有什么关系