考虑以下简单示例:

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,因为只有在进入或离开同步块时才在特定线程上强制进行读写刷新。因此,第一个线程将很乐意使用其缓存的值,而不知道它已被更改。

我知道使internalNum易变将解决可能的问题,但是我只是想知道天气是否真的必要。

最佳答案

假设代码执行分为两个线程。
  它不会退出。但是,资源(方法,字段)可以由两个线程以并行方式访问。


我想你把事情混了。您的类扩展了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();
    }
}


你的问题 :


  假设,发生以下事件序列:
  
  第一个线程访问getNum方法并缓存internalNum
  目前为0。同时第二个线程访问
  ModifyNum方法获取锁,将internalNum更改为1,然后
  退出释放锁。现在,第一个线程继续执行
  打印internalNum


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

internalNum += 1;


要么

 System.out.println(internalNum);

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

10-12 04:48