Java并发之synchronized(一)

synchronized是java关键字,用于给对象枷锁,保证单机的并发情况下线程安全。

锁的状态
|--------------------------------------------------------------------------------------------------------------|
|                                              Object Header (128 bits)                                        |
|--------------------------------------------------------------------------------------------------------------|
|                        Mark Word (64 bits)                                    |      Klass Word (64 bits)    |       
|--------------------------------------------------------------------------------------------------------------|
|  unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2 |     OOP to metadata object   |  无锁
|----------------------------------------------------------------------|--------|------------------------------|
|  thread:54 |         epoch:2      | unused:1 | age:4 | biased_lock:1 | lock:2 |     OOP to metadata object   |  偏向锁
|----------------------------------------------------------------------|--------|------------------------------|
|                     ptr_to_lock_record:62                            | lock:2 |     OOP to metadata object   |  轻量锁
|----------------------------------------------------------------------|--------|------------------------------|
|                     ptr_to_heavyweight_monitor:62                    | lock:2 |     OOP to metadata object   |  重量锁
|----------------------------------------------------------------------|--------|------------------------------|
|                                                                      | lock:2 |     OOP to metadata object   |    GC
|--------------------------------------------------------------------------------------------------------------|

在这里插入图片描述

测试
	引入
	<dependency>
        <groupId>org.openjdk.jol</groupId>
        <artifactId>jol-core</artifactId>
        <version>0.9</version>
    </dependency>

(JVM默认开启偏向锁,默认的偏向锁启动时间为4-5秒后,所以先让主线程睡5秒再加锁能保证对象处于偏向锁的状态,此处也可以在VM Options中添加参数
【-XX:BiasedLockingStartupDelay=0】来让JVM取消延迟启动偏向锁(本文的示例均未设置此参数),其效果跟不改变VM Options只在main方法中让主线程先睡眠5秒是一样的)
在这里插入图片描述

无锁

public class User {
    private String name;
    private Integer age;
}
测试锁
public class synTest {
    public static void main(String[] args) {
        User user = new User();
        System.out.println(ClassLayout.parseInstance(user).toPrintable());
	}
}

输出
com.util.lock.User object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 java.lang.String User.name null
16 4 java.lang.Integer User.age null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

偏向锁

默认偏向锁是延迟5秒开启
public static void main(String[] args) {
    try {
    	//延迟5秒保证偏向锁开启
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    User user = new User();
    System.out.println(ClassLayout.parseInstance(user).toPrintable());
}
com.util.lock.User object internals:

OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 java.lang.String User.name null
16 4 java.lang.Integer User.age null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
对象头标示位 101 偏向锁,但这是未加锁情况下所以线程id是空的。其余数据跟上述无锁状态一样。

加锁
 public static void main(String[] args) {
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    User user = new User();
    synchronized (user){
        System.out.println(ClassLayout.parseInstance(user).toPrintable());
    }
}

com.util.lock.User object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 48 72 03 (00000101 01001000 01110010 00000011) (57821189)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 java.lang.String User.name null
16 4 java.lang.Integer User.age null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
与上面对比多个线程id

轻量锁

不睡眠5秒,直接用synchronized给对象加锁
  public static void main(String[] args) {
    User user = new User();
    synchronized (user){
        System.out.println(ClassLayout.parseInstance(user).toPrintable());
    }
}

打印
com.util.lock.User object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) e8 f1 a8 02 (11101000 11110001 10101000 00000010) (44626408)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 java.lang.String User.name null
16 4 java.lang.Integer User.age null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
标示位为00.

重量

存在线程竞争的时候触发
 public static void main(String[] args) {
    User user = new User();
    Thread t1 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (user){
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(ClassLayout.parseInstance(user).toPrintable());
            }
        }
    });
    t1.start();

    Thread t2 = new Thread(new Runnable() {
        @Override
        public void run() {
            synchronized (user){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.err.println(ClassLayout.parseInstance(user).toPrintable());
            }
        }
    });
    t2.start();
}

打印
com.util.lock.User object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 4a 06 a7 1c (01001010 00000110 10100111 00011100) (480708170)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 java.lang.String User.name null
16 4 java.lang.Integer User.age null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

com.util.lock.User object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 4a 06 a7 1c (01001010 00000110 10100111 00011100) (480708170)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 java.lang.String User.name null
16 4 java.lang.Integer User.age null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

标示位10

hashCode会取消偏向锁

	public static void main(String[] args) {
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    User user = new User();
    synchronized (user){
        System.out.println(ClassLayout.parseInstance(user).toPrintable());
    }
    System.out.println(user.hashCode());
    System.out.println(ClassLayout.parseInstance(user).toPrintable());
}

com.util.lock.User object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 48 13 03 (00000101 01001000 00010011 00000011) (51595269)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 java.lang.String User.name null
16 4 java.lang.Integer User.age null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

1562557367
com.util.lock.User object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 b7 bb 22 (00000001 10110111 10111011 00100010) (582727425)
4 4 (object header) 5d 00 00 00 (01011101 00000000 00000000 00000000) (93)
8 4 (object header) 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
12 4 java.lang.String User.name null
16 4 java.lang.Integer User.age null
20 4 (loss due to the next object alignment)
Instance size: 24 bytes

经过hashcode。对象会从偏向锁变为无锁状态,即使后续给对象加锁,该对象也只会进入轻量级或者重量级锁状态,不会再进入偏向状态了。因为该对象一旦进行Object的hashCode计算,那么对象头中会保存这个hashCode,此时再也无法存放偏向线程的id了因为对象头的长度无法同时存放hashCode和偏向线程id),所以此后该对象无法再进入偏向锁状态。

锁的膨胀

开启偏向锁,new对象->无线程id的偏向锁->有线程id的偏向锁->锁交替运行清亮锁->线程存在竞争重量锁
new对象->无线程id的偏向锁->有线程id的偏向锁->存在竞争重量锁

。。。待续

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值