Java 使用 synchronized 时,我是否可以免费获得 volatile 功能?

标签 java multithreading concurrency synchronized volatile

我阅读了几篇关于并发问题的文章,但我仍然不确定某些事情。 我可以说当使用 synchronized 时,我可以免费获得 volatile 功能,因为当一个对象上的锁将被释放时,下一个线程总是读取修改后的对象。使用 volatile,对象的值会立即反射(reflect)到其他线程。但是当我使用synchronized时,由于对象上的锁,不可能立即反射(reflect)出来。当锁被释放时,只有这样另一个线程才能访问它。所以我不必关心立即将值反射(reflect)给其他线程。我理解的对吗?

[更新]
示例始终打印 1 2 3 4 5 6 7 8 9,不带 volatile。

package main;

public class Counter
{
    public static long count = 0;
}

public class UseCounter implements Runnable
{
    public void increment()
    {
        synchronized (this)
        {       
            Counter.count++;
            System.out.print(Counter.count + " ");
        }
    }

    @Override
    public void run()
    {
        increment();
        increment();
        increment();
    }
}

public class DataRace
{
    public static void main(String args[])
    {
        UseCounter c = new UseCounter();

        Thread t1 = new Thread(c);
        Thread t2 = new Thread(c);
        Thread t3 = new Thread(c);

        t1.start();
        t2.start();
        t3.start();
    }
}

最佳答案

不,根据 Java 内存模型,同步访问并不暗示 volatile 访问(尽管在特定实现中可能是这样,但您不应该依赖于此)

Java Language Specification 17.4.4 (on the Java Memory Model):

Synchronization actions induce the synchronized-with relation on actions, defined as follows:

  • An unlock action on monitor m synchronizes-with all subsequent lock actions on m (where "subsequent" is defined according to the synchronization order).

  • A write to a volatile variable v (§8.3.1.4) synchronizes-with all subsequent reads of v by any thread (where "subsequent" is defined according to the synchronization order).

volatile 对变量进行操作,synchronized 对对象的监视器(“锁”)进行操作。

如果一个线程 A 刚刚退出对象 O 上的同步块(synchronized block),而另一个线程 B 刚刚读取对象 上的易失变量(实例字段)V>O,那么两个线程之间仍然同步关系。无法保证线程 A 会看到线程 B 所做的任何数据修改,反之亦然,直到线程 B 也在对象 O 上同步,或者直到线程 A 也访问了可变字段 V 在对象 O 上。

关于Java 使用 synchronized 时,我是否可以免费获得 volatile 功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23180112/

相关文章:

go - 如何从 go routine 中退出外循环?

java - 在java中使用SHA1对密码进行哈希处理

用于零终止字符串的 Java BufferedReader

c - 不正确地使用 InterlockedCompareExchange 以原子方式复制值?

java - LinkedBlockingQueue.poll(...) 偶尔抛出 InterruptedException

c - Mutex 不同步 C++

java - 微服务和事务管理器如何处理并发问题

java - 使用 servlet 的 smack 连接

java - 如何在java上制作一个开/关按钮?

c++ - 如何使用构造函数(带参数)创建模板类并将该类的方法传递给线程