笔记 3 · synchronized

注意

synchronized 不能锁String、Integer、Long类型。
synchronized (this) 锁的是当前类的对象。 this关键字指向的是当前对象的引用。
synchronized (this.getClass()) 锁的是当前类的class对象。

synchronized 不能防止出现指令重排序的情况。

使用

// 一个有若干个synchronized方法的对象
class MyClass {
    public synchronized void hello() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("hello");
    }

    public synchronized void world() {
        System.out.println("world");
    }
}

class Test {
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        new Thread(()-> {
            myClass.hello();
        }).start();
        new Thread(()-> {
            myClass.world();
        }).start();
        
        // 输出
        // hello
        // world
    }
}
如果一个对象(这里指 myClass ),它里面有若干个synchronized方法,

当有多个线程对其访问时,在某一时刻,只能有唯一的一个线程进入,其中某个synchronized方法。其他的线程
即使访问的是其他的synchronized方法,也要等待。

原因:线程若要进入这个对象(例:myClass),执行某个方法。需要先获取到当前对象(类)的锁(即myClass的锁)。
而一个类,只有一个锁,所以一次只能有一个线程可以进入。

当某一个线程去访问 static synchronized 方法时,他获取到的锁就不是当前对象(例 myClass )的锁了,而是
当前对象所对应的class对象的锁。
public  static  synchronized void method2() { }
因为,静态方法并不属于当前对象,它属于当前对象所对应的class对象。
例:
MyClass myClass1 = new MyClass(); 		
MyClass myClass2 = new MyClass();
通过new关键字,一个类可以有多个对象(一个对象一把锁),但一个类对应的class对象,只有一个(一把锁)。

synchronized 是可重入锁,当某个线程获取到了对象(例:myClass )的锁,因为是同一个线程、同一把锁,所以
它也可以访问myClass 对象中其他的 synchronized方法。从而避免死锁。
例:
class MyClass {
    public synchronized void hello() {
        System.out.println("hello");
        world();
    }

    public synchronized void world() {
        System.out.println("world");
    }
}

一问
public class Test {
	public synchronized void method1() {
	}
	public void method2() {
	}
}

Test test =new Test();

问:在实例化一个对象 test后,假设线程A在执行method1方法,此时线程B可不可以执行同一个对象的
    method2方法?
二问
public class Test {
	public synchronized void method1() {
	}
	public synchronized void method2() {
	}
}

Test test =new Test();

问:在实例化一个对象 test后,假设线程A在执行method1方法,此时线程B可不可以执行同一个对象的
    method2方法?
三问
public class Test {
	public synchronized void method1() {
	}
	public static synchronized void method2() {
	}
}

Test test =new Test();

问:在实例化一个对象 test后,假设线程A在执行method1方法,此时线程B可不可以执行同一个对象的
    method2静态方法?

在这里插入图片描述

一问
可以,因为synchronized 方法,和非synchronized 方法可以同时运行。
二问
不可以,因为对于同一个对象来说,它所有的synchronized 方法,锁(monitor)的都是同一个东西( test )。
三问
可以,因为 method1() 方法的 synchronized 关键字,锁的是当前的对象(类:Test),
method2() 方法的 synchronized 关键字,锁的是当前的Test对象,所对应的class对象。

底层原理

  1. 当我们使用synchronized 关键字修饰代码块时,字节码层面上是通过monitorenter 与
    monitorexit 指令来实现锁的获取与释放动作。
    在这里插入图片描述

  2. 当线程进入到monitorenter 指令后,线程会持有被同步对象(例:括号内的object)
    的Monitor对象,执行monitorexit 退出指令后,线程会释放Monitor对象。

  3. 对于synchronized关键字修饰方法来说,并没有出现 monitorenter 与monitorexit 指令,
    而是出现了 ACC_SYNCHRONIZED标志。
    在这里插入图片描述

    原因:JVM使用ACC_SYNCHRONIZED访问标志区分一个方法是否为同步方法;当方法被调用时,调用指令会检查该方法是否拥有ACC_SYNCHRONIZED标志。如果有,那么执行线程将会现持有方法所在对象的Monitor对象,然后在执行方法体;在该方法执行期间,其他任何线程均无法在获取到这个Monitor对象。当线程执行完该方法后(即使是出现了异常),它会释放掉Monitor对象,

  4. 原则上来说,这个静态方法method,并不属于MyTest3这个类。因为,我们可以在
    MyTest3这个类,并没有生成任何对象的情况下,通过MyTest3这个类名,直接调用
    method()静态方法。 因为静态方法,不能使用this关键字,所以args_size = 0。
    在这里插入图片描述

到JDK1.6,对synchronized加入了很多优化措施,如:自适应自旋、锁消除、锁粗化、偏向锁、轻量级锁等。

在这里插入图片描述

注:资料主要来源【张龙

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值