12.0 Java中的volatile和synchronized之间的区别| Java Debug 笔记

125 阅读2分钟

本文正在参加「Java主题月 - Java Debug笔记活动」,详情查看<活动链接>

我想知道将变量声明为volatile和的synchronized(this)块中访问变量之间的区别?

对volatile变量的访问永远不会被阻塞:我们只做简单的读取或写入操作,因此与同步块不同,我们永远不会保持任何锁。

因为访问易失性变量永远不会持有锁,所以它不适用于我们希望以原子操作方式进行读取-更新-写入的情况(除非我们准备“错过更新”);

读-更新-写是什么意思? 写本身不就是更新吗,还是仅表示更新是取决于读取的写?

最重要的是,什么时候更适合将变量声明为volatile而不是通过同步块进行访问? 对依赖于输入的变量使用volatile是个好主意吗? 例如,有一个名为render的变量可以通过渲染循环读取并由keypress事件设置吗?

回答1:

volatile是字段修饰符,而同步修饰代码块和方法。 因此,我们可以使用这两个关键字来指定简单访问器的三种变体:

    int i1;
    int geti1() {return i1;}

    volatile int i2;
    int geti2() {return i2;}

    int i3;
    synchronized int geti3() {return i3;}

geti1()访问当前线程中当前存储在i1中的值。 线程可以具有变量的本地副本,并且数据不必与其他线程中保存的数据相同,特别是另一个线程可能在其线程中更新了i1,但是当前线程中的值可能与 该更新的值。 实际上,Java具有“主”内存的概念,这是保存变量的当前“正确”值的内存。 线程可以拥有自己的变量数据副本,并且线程副本可以与“主”内存不同。 因此,实际上,如果线程1和线程2都已更新,则“主”内存的i1值为1,线程1的i1值为2,线程2的i1值为3是可能的。 i1,但那些更新的值尚未传播到“主”内存或其他线程。

geti2()有效地从“主”内存访问i2的值。 易失性变量不允许具有与“主”内存中当前保存的值不同的变量的本地副本。 实际上,声明为volatile的变量必须在所有线程之间同步其数据,这样,无论何时在任何线程中访问或更新该变量,所有其他线程都会立即看到相同的值。 通常,易失性变量比“普通”变量具有更高的访问权限和更新开销。 通常,为了提高效率,允许线程拥有自己的数据副本。

加锁就是同时只有一个人可以修改(甚至可能只有一个人读,看具体优化了,通过这种方式防止冲突的产生)