让我们假设这样:
查看ArrayList源代码,我们可以看到size和elementData字段不是易变的:
transient Object[] elementData; // non-private to simplify nested class access
private int size;
另外,让我们看看add方法:
/**
* This helper method split out from add(E) to keep method
* bytecode size under 35 (the -XX:MaxInlineSize default value),
* which helps when add(E) is called in a C1-compiled loop.
*/
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
这样的事情会发生吗?
ElementData是否也会出现类似的情况?
TL;DR:在正确的同步下,您描述的问题是不可能的,因为同步确保了操作的原子性和可见性。
JVM执行Java代码的方式相当复杂。可以自由地对与Java代码中的表达式和语句相对应的指令进行重新排序,以便更高效地执行它们,前提是您不能分辨出某个线程对其操作进行了重新排序。
从本质上说,这就像一个老板说“我不在乎你如何完成工作,只要在某个时候完成工作就行了”。
它的困难在于,虽然它说你不能看到一个线程内的重新排序,但它并没有说不同的线程不能看到彼此以不同的顺序做事情。
这是令人头晕目眩的东西。简化的概念是发生之前的想法。您可以在两个线程中执行某些操作,以确保在另一个线程尝试使用它们的结果时,一个线程执行的操作似乎已经发生。从字面上看,一个线程中的事情“发生在”另一个线程中的事情之前。(继续做工作类比,这就像你必须把你已经完成的工作交给一个同事,让他们来做他们的工作:他们可以接受你已经完成的工作,去做他们的工作,而不管你是如何完成的)。
有许多众所周知的事情创造了发生之前的关系。与本问题有关的是:
因此,volatile和synchronized都是创建happens的两种方法--在此之前,这是为了保证一个线程所做的事情被另一个线程看到。
但两者是有区别的:
在添加到arraylist
的情况下,需要原子性,因为您要做的不止一件事:增加大小并分配新的数组元素。
使变量也变得易变,在正确性方面没有任何作用,但在模态情况下会使代码变慢,在模态情况下,arraylist
只能从单个线程访问。
因此,如果您的代码是正确同步的,也就是说,对列表的所有访问都在同一件事情上同步,例如在列表本身上同步,那么您描述的情况就不会发生,因为同步的原子性和可见性属性。
我尝试使用ArrayList解决生产者和消费者问题(我知道ArrayList是nt threadsafe),我确保使用关键字放置列表,但仍然进入。这就是错误 启动生产者请提供作业详细信息:TestJob作业完成:TestJob Exception位于java.util.ArrayList$itr.checkforcoModification(未知源)位于test.thread.consumer.r
考虑以下代码: 在一次采访中,我被问到了以下问题:如果只有一个线程调用,而多个线程可以调用,那么这个代码是线程安全的吗? 我知道,如果我们有多个写入线程,竞争条件可能会发生。然而,当每个读取线程中只有一个写入线程时,我们将按顺序获取值,即我们不会在之后读取,因为的写入发生在第一次读取,因此,在同一线程中的所有后续读取。这个推理是正确的,还是我漏掉了什么?
最近我在读一些关于java并发的书。关于线程安全,如果不可能使一个类变为inmutable,那么可以通过同步它的数据来确保线程安全。 下面的类显然不是线程安全的 然后我可以同步写,但它不会保持线程安全 因为我不仅需要同步写入,还需要同步读取 现在的问题是,通过使用易失性,我可以保证其他线程会看到更新的值,所以这让我认为这个类应该是线程安全的 最后一个类线程安全吗??
问题内容: 我在想,如果您有一个静态方法 不 同步,但并 没有 修改任何静态变量是线程安全的?如果该方法在其中创建局部变量该怎么办?例如,以下代码是线程安全的吗? 因此,如果我有两个线程连续且同时调用此方法,一个带狗(例如“大丹狗”和“斗牛犬”),另一个带猫(例如“波斯”和“暹罗”)的猫,我将得到猫和狗在同一阵列中?还是猫和狗永远不会同时处于该方法的同一调用中? 问题答案: 此方法是100%线程安
如果我决定使用一个非线程安全的集合并同步它的访问,我是否需要同步构造函数中的任何突变?例如,在下面的代码中,我知道对列表的引用在构造后对所有线程都是可见的,因为它是最终的。但我不知道这是否构成安全发布,因为构造函数中的add没有同步,而且它正在ArrayList的elementData数组中添加一个引用,这是非最终的。
我要创建一个程序,给定N个线程,这些线程可以在队列中插入或删除一个元素,但是线程访问队列是有条件的: null 我用同步块做的,就像这样: run void很简单,它只是在插入或删除元素时永远循环。 我的问题是,在不使用synchronized的情况下,我如何遵循那个条件? 没有同步块,怎么可能保证互斥呢? 编辑:我不能使用类似于同步的东西(就像锁一样)