Java会不会同步块更改?

时间:2019-05-23 18:48:18

标签: java multithreading

private Object x = new Object();

public void doA() {
   synchronized(x){
       x = new Object();
       //do something
    }
}

public void doB() {
    synchronized(x) {
        //do something 
    }
}

doA()doB()同时被调用,但doA()首先进行。因此B将被阻止,直到doA()完成

即使doA()x = new x调用中修改了x,这是否成立?还是在x = new x doA()中的这一行doB()之后,由于x发生了变化,将不再被阻止?

3 个答案:

答案 0 :(得分:3)

究竟发生了什么,实际上取决于doA()的运行速度:

如果doA()x到达其同步块之前更改了doB()的值,则doB()将锁定{ {1}}已创建。

如果doA()快速并且doB()部分得到评估,而synchronized(x)可以更改doA()的值,那么x将不得不等到{ {1}}的{​​{1}}块结束。

说明

每当Java使用任一方法访问doB()代码时,它都会评估变量doA(),该变量为Java提供一个对象。因此,Java然后尝试锁定该对象,并保持锁定状态。或者,如果该对象上已经有一个锁,它将等待该锁消失。 (每当Java到达synchronized代码时,它都会获取变量的值,而忽略变量本身的遗忘,因此以后您可以随意更改变量,但是锁定和锁定检查仍会在变量的先前值上进行。 )

答案 1 :(得分:2)

我的好奇心得到了我的最好的帮助,我编写了此测试来验证会发生什么。该锁仍保留在原始参考上,并且不会更改。

import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class Test {

    private static Object x = new Object();

    public static void main(String[] args) throws Exception {
        Test a = new Test();
        Test b = new Test();

        Thread t = new Thread(a.new MyRunnable());
        t.start();
        Thread.sleep(100);
        b.doB();
    }

    public void doB() {
        System.out.println("here b");
        synchronized (x) {
            System.out.println("here sync b");
        }
        System.out.println("here done sync b");
    }

    public class MyRunnable implements Runnable {

        public MyRunnable() {
        }

        public void run() {
            System.out.println("here a");
            synchronized (x) {
                System.out.println("here sync a");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }

                x = new Object();

                System.out.println("here new object a");
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("here after sleep a");
            }
            System.out.println("here done sync a");
        }
    }

}

输出如下。显然,即使重新分配后,该锁仍然保留在原始参考上。

here a
here sync a
here b
here new object a
here after sleep a
here done sync a
here sync b
here done sync b

答案 2 :(得分:1)

我认为doA()方法仍将锁定旧的“ x”。除非线程保持完成对同步块的处理,否则不会通知其他等待锁定“ x”的线程。 同步块完成后,线程将争夺对x新实例的锁定。