并发编程三个重要特性|青训营

48 阅读2分钟

原子性 一次操作或者多次操作,要么所有的操作全部都得到执行并且不会受到任何因素的干扰而中断,要么都不执行。 在 Java 中,可以借助synchronized、各种 Lock 以及各种原子类实现原子性。 synchronized 和各种 Lock 可以保证任一时刻只有一个线程访问该代码块,因此可以保障原子性。各种原子类是利用 CAS (compare and swap) 操作(可能也会用到 volatile或者final关键字)来保证原子操作。 可见性 当一个线程对共享变量进行了修改,那么另外的线程都是立即可以看到修改后的最新值。 在 Java 中,可以借助synchronized、volatile 以及各种 Lock 实现可见性。 如果我们将变量声明为 volatile ,这就指示 JVM,这个变量是共享且不稳定的,每次使用它都到主存中进行读取。 有序性 由于指令重排序问题,代码的执行顺序未必就是编写代码时候的顺序。 我们上面讲重排序的时候也提到过: 指令重排序可以保证串行语义一致,但是没有义务保证多线程间的语义也一致 ,所以在多线程下,指令重排序可能会导致一些问题。 在 Java 中,volatile 关键字可以禁止指令进行重排序优化。 volatile 关键字 在 Java 中,volatile 关键字可以保证变量的可见性,如果我们将变量声明为 volatile ,这就指示 JVM,这个变量是共享且不稳定的,每次使用它都到主存中进行读取。 volatile 关键字能保证数据的可见性,但不能保证数据的原子性。synchronized 关键字两者都能保证。 在 Java 中,volatile 关键字除了可以保证变量的可见性,还有一个重要的作用就是防止 JVM 的指令重排序。 如果我们将变量声明为 volatile ,在对这个变量进行读写操作的时候,会通过插入特定的 内存屏障 的方式来禁止指令重排序。