锁的实现原理—3,Synchronized实现理解

java语言、Java虚拟机规范—官方文档
Synchronized概述:用法、作用
  • 用法:修饰代码块、方法。PS:听说叫类锁和对象锁
  • 作用:(个人理解) 在多线程环境下,通过Synchronized关键字,使其多个线程按照一定的先后顺序执行,从而保证单一线程安全。 PS:在此处使用Synchronized的一组同步集:当一个线程释放锁之后,另一个线程才能获取锁。
JVM中的同步实现方式
  • 原文描述地址:3.14. Synchronization 其他类似描述信息:2.11.10. Synchronization
  • JVM通过控制对象所关联的monitor的进入和退出实现同步,对于monitor进入和退出的调用,可以是显示的,也可以是隐式的。
  • 在Java语言编码中,最常见的同步是对于方法的同步,方式的同步并不是显示的通过monitorenter和monitorexit实现,取而代之的是通过运行时常量池ACC_SYNCHRONIZED标记实现,此标识,将会在方法的调用中执行检查。
  • 对于代码块的同步,使用monitorenter和monitorexit编译之后的效果如下:
void onlyMe(Foo f) {
    synchronized(f) {
        doSomething();
    }
}
Method void onlyMe(Foo)
0   aload_1             // Push f
1   dup                 // Duplicate it on the stack
2   astore_2            // Store duplicate in local variable 2
3   monitorenter        // Enter the monitor associated with f
4   aload_0             // Holding the monitor, pass this and...
5   invokevirtual #5    // ...call Example.doSomething()V
8   aload_2             // Push local variable 2 (f)
9   monitorexit         // Exit the monitor associated with f
10  goto 18             // Complete the method normally
13  astore_3            // In case of any throw, end up here
14  aload_2             // Push local variable 2 (f)
15  monitorexit         // Be sure to exit the monitor!
16  aload_3             // Push thrown value...
17  athrow              // ...and rethrow value to the invoker
18  return              // Return in the normal case
Exception table:
From    To      Target      Type
4       10      13          any
13      16      13          any
  • 每个方法执行完成(正常或者异常)时,编译器会确保调用了一组相匹配的monitorenter和monitorexit方法。以确保,异常处理程序在捕捉异常后,能够为每一个相关联的执行代码执行monitorexit指令。
对象锁和类锁的区别
  • 对象锁和类锁,其在本质上是一致的。这种一致性表现在:1,均是通过monitorenter和monitorexit指令实现。2,均只是一个资源被标识持有的符号。
  • 对象锁和类锁不一样的地方:1,一个ClassA,它能有多个实例对象,但它只会有一个class对象。所以,当对象实例只有一个时,对象锁和类锁都差不多。2,类锁会存放标识字面量到运行时常量池,而对象锁随着编译后的代码,会存放在静态常量池。
一些代码示例
实例方法同步
public class SynchronizedClass {

    public synchronized void methodA(String name) {
       System.out.println(name);
    }

    public synchronized void methodB(String name) {
        System.out.println(name);
    }
    
}
  • 我在工作中有见过这样的代码,我猜测写代码的最初预期,是希望多个线程执行A的时候同步阻塞,多个线程执行B的时候同步阻塞。但,coder是预期可以并发同时执行A和B的。结合到一般开发过程中的情况,这段代码可能会出什么问题?在什么情况下,这段代码又能够实现coder的预期?
  • 像一般的话,采用springIOC管理bean,用的基本都是单例。对于一个SynchronizedClass来讲,它只有一个实例对象,也只有一个class对象,那么这个地方其实就等价了。 一旦一个线程拿到这个对象的monitor锁,比如调用了A方法,执行了moniterenter指令,那么别的线程是会在调用B方法时进行阻塞的,因为一个对象只会关联一个monitor对象。但假设spring的bean生成采用的是原型,coder的预期就实现了。
类方法同步/静态方法同步
public class SynchronizedClass {

    public static synchronized void methodC(String name){
        System.out.println(name + "哒哒");
    }

    public static void methodD(String name){
        synchronized (SynchronizedClass.class){
            System.out.println(name + "class");
        }
    }

}
  • 不确定一个类会被生成几个实例对象,比如单例就一个,原型多个。如果一个方法要实现对于所有的线程执行进行同步,这时候用类锁可能会更合适。PS:有点事情打乱了, 脑壳子嗡嗡的。
Redis可重入锁问题
  • 不管是对象锁还是类锁,假如我整多个JVM载入程序启动,然后似乎也锁不住呵。这时候才是不是就需要分布式锁了呀。。。啊啊啊啊啊。。。。。
  • 用Redis实现一个可重入的锁:比如classA,用Redis的setNX指令,设置一个key值为classA,然后value值为当前的线程信息。 这样,当我再次进入一个锁的时候,如果我发现value值是我当前的线程,就直接进入。 有木有大佬可以说说这个东西会出啥问题呀?啊啊啊啊啊啊啊啊啊。。。。我。。。。。
  • 我跟郭猴子,是真的无敌,巨无敌。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
synchronized关键字是Java中用于实现线程同步的关键字。它可以应用于方法或代码块,确保在同一时间只有一个线程能够访问被synchronized修饰的代码块或方法。 实现原理主要包括以下几个方面: 1. 监视器(Monitor Lock):每个Java对象都有一个监视器,可以抽象地理解为对象内部的一种标记。当一个线程访问synchronized代码块或方法时,它会尝试获取对象的监视器,如果获取成功,则进入临界区执行代码;如果获取失败,则线程进入阻塞状态,直到获得为止。 2. 内存屏障(Memory Barrier):synchronized关键字不仅保证了互斥性(即同一时间只有一个线程能够执行synchronized代码块或方法),还保证了可见性和有序性。在释放之前,会将对共享变量的修改刷新到主内存中;在获取之前,会从主内存中重新读取共享变量的值,确保每个线程看到的共享变量值一致。 3. 重入性(Reentrancy):synchronized关键字是可重入的,即同一个线程可以多次获取同一个对象的监视器而不会发生死。每次获取时,的计数器会递增,释放时计数器递减,只有当计数器为0时才真正释放。 4. 互斥性(Mutual Exclusion):synchronized关键字保证了临界区的互斥性,同一时间只有一个线程能够执行被synchronized修饰的代码块或方法。其他线程需要等待当前占用的线程释放后才能继续执行。 需要注意的是,synchronized关键字只能用于同一个进程或线程内部的同步,不能用于不同进程或线程之间的通信和同步。在Java 5及之后,还引入了更灵活的Lock和Condition接口来替代synchronized关键字,提供了更多高级的线程同步操作和更细粒度的控制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值