一个线程所做的更改不会反映在另一个线程中

时间:2018-09-12 09:18:25

标签: java multithreading synchronization thread-safety

我已经开始深入学习线程,并试图理解我编写的以下代码的概念,但是我不确定代码的输出。以下是我编写的代码,

public class UnsafeCheck extends Thread {
    private static Person person;


    // This method is not thread safe without synchronization. Make the method 
    // synchronized to make the code thread safe.
    public synchronized Person getPerson() {
        if(person == null) {
            System.out.println("Inside if block");
            person = new Person("Kilarapu Yethendra", 27);
        }
        return person;
    }

    public void run() {
        System.out.println("thread's run method");
        getPerson();
    }

    public static void main(String[] args) {
        UnsafeCheck uc = new UnsafeCheck();
        uc.start();

        UnsafeCheck uc1 = new UnsafeCheck();
        uc1.start();

        UnsafeCheck uc2 = new UnsafeCheck();
        uc2.start();        
    }   
}

输出:

thread's run method
Inside if block
thread's run method
Inside if block
thread's run method
Inside if block

如果我们观察到线程uc所做的输出更改未反映在线程uc1中,这就是为什么每个线程控制都转到if块的原因。 我希望当uc1执行run方法时人员引用会被初始化,但是uc1线程的人员仍然为空。

我进行的另一项有趣的观察是,如果将getPerson()方法设置为静态,则会得到预期的输出。以下是getPerson()方法为静态时的输出。

输出:

thread's run method
Inside if block
thread's run method
thread's run method.

请帮助我理解流程。

2 个答案:

答案 0 :(得分:1)

将您的方法声明为

public synchronized Person getPerson()

表示它正在使用包含的UnsafeCheck实例(即this)作为监视器来同步访问。在创建三个不同的UnsafeCheck实例时,它们中的每个实例都有其自己的锁,并且代码无法执行您期望的操作。

使用

public static synchronized Person getPerson()

在所有实例(即UnsafeCheck.class)上使用的监视器都是相同的,并且您为static Person变量获得了正确的同步。

有关synchronized方法的更多信息,请查看Oracle教程:Synchronized Methods

答案 1 :(得分:0)

好吧,现在我知道您在做什么,标题令人误解。监视器的synced关键字以对象为单位对其进行锁定,因此只有一个线程可以进入方法PER Object。

您可以做两件事来使它在整个应用程序范围内:

1.make getPerson方法为静态(它将在整个应用程序范围内同步)

2。使用允许您拾取同步对象的同步块(通常是“ this”用于对象同步,而“ UnsafeCheck.class”则用于整个应用程序)