Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 理解发生在同步之前_Java_Multithreading_Java Memory Model - Fatal编程技术网

Java 理解发生在同步之前

Java 理解发生在同步之前,java,multithreading,java-memory-model,Java,Multithreading,Java Memory Model,我试图理解Java的概念,但有几件事情看起来非常混乱。据我所知,before只是一组操作上的一个命令,不提供任何关于实时执行顺序的保证。实际上(强调我的): 应该注意的是,一段感情的出现先于一段感情 两个行动之间的差距并不一定意味着他们必须采取行动 在实现中按该顺序放置如果重新排序产生 结果与合法执行一致,并不违法。 因此,它所说的是,如果有两个动作,hb(w,r),那么在执行过程中,r可能在w之前发生,但不能保证它会发生。此外,读r也观察到写入w 如何确定在运行时中随后执行两个操作?例如: p

我试图理解Java的概念,但有几件事情看起来非常混乱。据我所知,before只是一组操作上的一个命令,不提供任何关于实时执行顺序的保证。实际上(强调我的):

应该注意的是,一段感情的出现先于一段感情 两个行动之间的差距并不一定意味着他们必须采取行动 在实现中按该顺序放置如果重新排序产生 结果与合法执行一致,并不违法。

因此,它所说的是,如果有两个动作,hb(w,r),那么在执行过程中,
r
可能在
w
之前发生,但不能保证它会发生。此外,读
r
也观察到写入
w

如何确定在运行时中随后执行两个操作?例如:

public volatile int v;
public int c;
行动:

Thread A
v = 3;  //w

Thread B
c = v;  //r

这里我们有
hb(w,r)
,但这并不意味着
c
在赋值后将包含值
3
。我如何强制
c
分配3?是否提供了这样的保证?

我想将上述语句与一些示例代码流相关联

为了理解这一点,让我们学习下面的类,它有两个字段
counter
isActive

class StateHolder {
    private int counter = 100;
    private boolean isActive = false;

    public synchronized void resetCounter() {
            counter = 0;
            isActive = true;
    }

    public synchronized void printStateWithLock() {
        System.out.println("Counter : " + counter);
        System.out.println("IsActive : " + isActive);
    }

    public void printStateWithNoLock() {
        System.out.println("Counter : " + counter);
        System.out.println("IsActive : " + isActive);
    }
}
并假设有三个线程T1、T2、T3在
状态持有者的同一对象上调用以下方法:

T1同时调用
resetCounter()
和T2调用
printStateWithLock()
,T1获得锁
T3->在T1完成执行后调用
printStateWithNoLock()

应该注意的是,两个动作之间的“先发生后发生”关系的存在并不一定意味着它们必须在实现中按该顺序发生。如果重新排序产生的结果与合法执行一致,则不违法

直接的电话说

如上所述,它为JVM、操作系统或底层硬件提供了在
resetCounter()
方法中对语句重新排序的灵活性。当T1被执行时,它可以按以下顺序执行语句

    public synchronized void resetCounter() {
            isActive = true;
            counter = 0;
    }
这与语句一致,并不一定意味着它们必须在实现中按该顺序发生。

现在从T2的角度来看,这种重新排序没有任何负面影响,因为T1和T2都在同一个对象上同步,T2保证看到两个字段的更改,而不管重新排序是否发生,就像关系之前发生的一样。因此,输出将始终是:

Counter : 0
IsActive : true
这是根据声明,如果重新排序产生与合法执行一致的结果,则它不是非法的

但从T3的角度来看,通过这种重新排序,T3可能会将
isActive
的更新值视为'true
,但仍然将
计数器
值视为
100',尽管T1已完成其执行

Counter : 100
IsActive : true
上述链接中的下一点进一步澄清了该声明,并表示:

更具体地说,如果两个操作共享一个“发生在”关系,则它们不必按照该顺序出现在它们不共享“发生在”关系的任何代码中。例如,处于数据竞争中的一个线程中的写操作与另一个线程中的读操作可能会出现顺序错误

在本例中,T3遇到了这个问题,因为它与T1或T2之间没有任何关系。这是与内联的,对于他们不共享“先发生后发生”关系的任何代码,不一定要以该顺序出现。

注意:为了简化这种情况,我们使用单线程T1修改状态,T2和T3读取状态。有可能

T1将
计数器更新为0
,稍后
T2将isActive修改为
true
,并在一段时间后看到
计数器为0
打印状态的T3仍然只能将isActive视为true,但计数器为100,尽管T1和T2都已完成执行

Counter : 100
IsActive : true
关于最后一个问题:

我们有hb(w,r),但这并不意味着赋值后c将包含值3。我如何强制c被赋值为3

由于
v
是一种易失性,根据

对易失性字段(§8.3.1.4)的写入发生在该字段的每次后续读取之前


因此,可以安全地假设,当线程B尝试读取变量
v
时,它将始终读取更新后的值,
c
将在上述代码中分配3。

当JLS表示线程A中的某个事件X与线程B中的事件Y建立了“发生在之前”的关系时,这并不意味着X将在Y之前发生

这意味着如果X发生在Y之前,那么两个线程都会同意X发生在Y之前。也就是说,两个线程都会看到程序内存的状态与X发生在Y之前的状态一致


这都是关于记忆的。线程通过共享内存进行通信,但是当一个系统中有多个CPU,所有CPU都试图访问同一个内存系统时,内存系统就会成为瓶颈。因此,典型的多CPU计算机中的CPU可以延迟、重新排序和缓存内存操作,以加快速度

当线程之间不进行交互时,这种方法非常有效,但当它们确实想要交互时,就会出现问题:如果线程A将一个值存储到一个普通变量中,Java就不能保证线程B何时(甚至是否)进行交互
// Definition: Some variables
private int first = 1;
private int second = 2;
private int third = 3;
private volatile boolean hasValue = false;

// Thread A
first = 5;
second = 6;
third = 7;
hasValue = true;

// Thread B
System.out.println("Flag is set to : " + hasValue);
System.out.println("First: " + first);  // will print 5
System.out.println("Second: " + second); // will print 6
System.out.println("Third: " + third);  // will print 7
public volatile int v;
public int c;
Actions:

Thread A
v = 3;  //w

Thread B
c = v;  //r
int v = 0;
int c = 0;
volatile boolean assigned = false;
v = 3;
assigned = true;
while(!assigned);
c = v;
int v = 0;
int c = 0;
boolean assigned = false;
v = 3;
assigned = true;
while(!assigned);
c = v;