如果synchronized锁住一个对象的不同变量或方法,会形成竞态条件吗?synchronized背后的原理是什么?

先看一个实验:

//分别尝试去锁一个对象的成员变量,成员方法,静态变量,静态方法,
//class对象以及对象本身,哪些操作会形成静态条件?
public class TestObj {
    private String field1 = "123";
    private static String field2 = "456";
    private String field3;
    private String field4;

    public void normalMethod() {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = format.format(date);
        System.out.println(time+":普通方法");
        try {
            Thread.sleep(5000);
            System.out.println(format.format(new Date())+":"+Thread.currentThread().getName());

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void lockMethod() {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = format.format(date);
        System.out.println(time+":锁定普通方法");
        try {
            Thread.sleep(5000);
            System.out.println(format.format(new Date())+":"+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static synchronized void lockStaticMethod() {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = format.format(date);
        System.out.println(time+":锁定静态方法");
        try {
            Thread.sleep(5000);
            System.out.println(format.format(new Date())+":"+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void lockField() {
        synchronized (field1) {
            Date date = new Date();
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String time = format.format(date);
            System.out.println(time+":锁定普通变量");
            try {
                Thread.sleep(5000);
                System.out.println(format.format(new Date())+":"+Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void lockStaticField() {
        synchronized (field2) {
            Date date = new Date();
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String time = format.format(date);
            System.out.println(time+":锁定静态变量");
            try {
                Thread.sleep(5000);
                System.out.println(format.format(new Date())+":"+Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public void lockStaticClass() {
        synchronized (TestObj.class) {
            Date date = new Date();
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String time = format.format(date);
            System.out.println(time+":锁定class对象");
            try {
                Thread.sleep(5000);
                System.out.println(format.format(new Date())+":"+Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void normalField() {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = format.format(date);
        System.out.println(time+":普通字段:"+field1);
        try {
            Thread.sleep(5000);
            System.out.println(format.format(new Date())+":"+Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class Main {
    public static void main(String[] args) {
        TestObj obj = new TestObj();
        Thread thread1 = new Thread(() -> {
            obj.lockStaticField();
        }, "1");
        Thread thread2 = new Thread(() -> {
            obj.lockStaticClass();
        }, "2");
        Thread thread8 = new Thread(() -> {
            TestObj.lockStaticMethod();
        }, "8");
        Thread thread3 = new Thread(() -> {
            obj.lockMethod();
        }, "3");
        Thread thread4 = new Thread(() -> {
            obj.lockField();
        }, "4");
        Thread thread5 = new Thread(() -> {
            obj.normalMethod();
        }, "5");
        Thread thread6 = new Thread(() -> {
            obj.normalField();
        }, "6");
        Thread thread7 = new Thread(() -> {
            synchronized (obj) {
                Date date = new Date();
                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String time = format.format(date);
                System.out.println(time + ":锁定普通对象");
                try {
                    Thread.sleep(5000);
                    System.out.println(format.format(new Date()) + ":" + Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "7");

        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
        thread5.start();
        thread6.start();
        thread7.start();
        thread8.start();
    }
}

公布答案:

2021-06-04 13:29:41:锁定class对象
2021-06-04 13:29:41:普通方法
2021-06-04 13:29:41:普通字段:123
2021-06-04 13:29:41:锁定普通方法
2021-06-04 13:29:41:锁定静态变量
2021-06-04 13:29:41:锁定普通变量
2021-06-04 13:29:46:6
2021-06-04 13:29:46:2
2021-06-04 13:29:46:1
2021-06-04 13:29:46:4
2021-06-04 13:29:46:3
2021-06-04 13:29:46:5
2021-06-04 13:29:46:锁定静态方法
2021-06-04 13:29:46:锁定普通对象
2021-06-04 13:29:51:8
2021-06-04 13:29:51:7

反复尝试,发现可见锁静态方法会与锁class对象形成竞态条件,锁普通方法会与锁普通对象形成竞态条件

Synchronized原理:

synchronized的底层依赖于Monitor对象,即管程控制对象并发访问机制的具体实现

1.对象内存布局

hotspot虚拟机中,对象内存分为三块区域:

  • 对象头(Header)
  • 实例数据(Instance Data)
  • 对齐填充(padding)

image.png

1.1 对象头Header

header主要包含markword和对象指针KlassPointer,如果是数组的话,还包含数组的长度
image.png

image.png
image.png


AshShawn
6 声望2 粉丝