先行发生原则

并发

Posted by CHuiL on April 18, 2021

先行发生原则可以用来判断并发环境下数据是否存在竞争,线程是否安全得非常有用得手段。用来判断解决并发环境下两个操作之间是否可能存在冲突的所有问题;

满足以下规则的操作,即没有冲突,线程安全;

程序次序规则

同一个线程内,书写在前面得操作先行发生与书写在后面的操作;前面的代码的执行结果对于==依赖它的==后面代码来说是可见的;

 int a = 3;//代码1
 int b = a + 1; //代码2

这里代码2依赖到了代码1的结果,所以系统会保证这两段代码的执行顺序,即代码1会在代码2执行之前执行,并且在同一个线程中,代码1的结果对代码2肯定是可见的;

 int a = 3;//代码1
 int b = 2;//代码2

这里1,2之间灭有依赖关系,所以代码2可能在代码1之前执行;

 int a = 3; //代码1
 int c = 4; //代码2
 int b = a + 1;//代码3

在上面这段代码中,1 3 之间有依赖关系,所以顺序一定是13;但是2的执行顺序与1,3无关,所以代码2可能会在 13之前,13之间或者13之后;

管程锁定规则

一个unLock操作先行发生于后面对同一个锁的lock操作;同一个锁只能由线程持有;

volatile变量规则

对一个volatile变量的写操作先行发生于后面对这个变量的读操作;

volatile int a;
//线程1执行内容
public void method1() {
    a = 1;
}
//线程2执行内容
public void method2() {
    int b = a;
}

若线程1先执行,由于a为volatile变量,根据volatile规则可以保证线程2后执行时能读取到最新的结果(注意,这条规则值得是1先执行的情况,如果线程1先执行了method1,但是 a = 1的代码后执行于线程2 的 int b = a;则b读取的依旧还是旧值)

传递性

如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C

volatile int var;
int b;
int c;
//线程1执行内容
public void method1() {
    b = 4; //1
    var = 3; //2
}
//线程2执行内容
public void method2() {
    c = var; //3
    c = b; //4
}

根据程序次序规则,从结果来看1先执行于2 3先执行于4(因为彼此之间没有依赖,所以12 21,34 43是等同的);如果2先执行于3,由volatile变量保证了3可以读取到2的结果;所以可以得出1先行于3,1先行于4; 但是如果执行执行顺序为 1 3 4 2; 2 3之间无法满足 先2 后 3,也就无法满足volatile规则,无法得出1先行于3,4;