Java同步与数据一致性

标签 java memory synchronized volatile flush

考虑以下简单示例:

public class Example extends Thread {
    private int internalNum;

    public void getNum() {
        if (internalNum > 1)
            System.out.println(internalNum);
        else 
            System.out.println(1000);
    }

    public synchronized modifyNum() {
        internalNum += 1;
    }

    public void run() {
        // Some code
    }
}

假设代码执行分为两个线程。假设,会发生以下事件序列:

  • 第一个线程访问getNum方法并缓存当前为0的internalNum
  • 与此同时,第二个线程访问 modifyNum 方法获取锁,将 internalNum 更改为 1 并退出释放锁。
  • 现在,第一个线程继续执行并打印 internalNum

问题是控制台上会打印什么?

我的猜测是,这个假设的示例将导致 1000 打印在控制台上,因为只有在进入或离开同步块(synchronized block)时才会在特定线程上强制进行读写刷新。因此,第一个线程将愉快地使用它的缓存值,而不知道它已更改。

我知道使 internalNum volatile 可以解决可能的问题,但我只是想知道它是否真的有必要。

最佳答案

Let's say code execution is split in two threads. It doesn't exit. However a ressource (method, fields) may be accessed in concurrent way by two threads.

我认为你把东西混在一起了。您的类扩展了Thread,但您的问题是关于通过并发线程访问同一实例的资源。

这是适合您的问题的代码。

线程之间的共享资源:

public class SharedResource{
    private int internalNum;

    public void getNum() {
        if (internalNum > 1)
            System.out.println(internalNum);
        else 
            System.out.println(1000);
    }

    public synchronized modifyNum() {
        internalNum += 1;
    }

    public void run() {
        // Some code
    }   
}

线程和运行代码:

public class ThreadForExample extends Thread {

    private SharedResource resource;

    public ThreadForExample(SharedResource resource){
       this.resource=resource;
    }

    public static void main(String[] args){
       SharedResource resource = new SharedResource();
       ThreadForExample t1 = new ThreadForExample(resource);
       ThreadForExample t2 = new ThreadForExample(resource);
       t1.start();
       t2.start();
    }
}

您的问题:

Hypothetically, following sequence of events occurs:

First thread accesses the getNum method and caches the internalNum which is 0 at the moment. At the very same time second thread accesses modifyNum method acquiring the lock, changes the internalNum to 1 and exits releasing the lock. Now, first thread continues it execution and prints the internalNum

在您的场景中,您给人的印象是 modifyNum() 方法执行会阻止其他线程访问非同步方法,但事实并非如此。
getNum() 未同步。因此,线程不需要获取对象上的锁来执行它。在这种情况下,输出仅取决于哪个线程首先执行了指令:

internalNum += 1;

 System.out.println(internalNum);

关于Java同步与数据一致性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41533796/

相关文章:

Java 扫雷 - ArrayIndexOutOfBounds 异常

尝试更新字符串字段时出现 java.sql.SQLSyntaxErrorException

java - Cookie.setMaxAge(Integer.MAX_VALUE) 是怎么回事?

python - 如何释放python删除对象的内存?

c - C中的别名内存

java - Guava 约束发生了什么?

java - 是否有任何有效和优化的方法来在 long[] 数组中存储 500M+ 元素?

ios - 允许一次调用一个类别方法 ios (@synchronized)

java - 同步线程抛出 CurrentModificationException

java - 为什么要在多线程环境下使用HashMap?