Synchronized、 Volatile、ReentrantLock

Synchronized的实现原理

  • synchronized 的使用方式有如下几种
    在这里插入图片描述
  • 线程状态及状态转换
    在这里插入图片描述
  • synchronized实现何时使用了自旋锁?
    在线程进入 ContentionList 时,即第一步操作前,线程在进入等待队列时首先进行自旋锁尝试获得锁,如果不成功再进入等待队列。
  • synchronized原理
    -Java虚拟机的同步(Synchronization)是基于进入和退出 Monitor 对象实现,无论是显式同步(有明确的 monitorenter 和 monitorexit 指令,即同步代码块)还是隐式同步都是如此。同步方法并不是由 monitorenter 和 monitorexit 指令来实现的,而是由方法调用指令读取运行时常量池中方法的ACC_SYNCHRONIZED 标志来隐式实现的。
    对如下同步代码块进行 javap 反编译
    在这里插入图片描述
    反编译后的代码如下:
    在这里插入图片描述
    可以看到 含有 monitorenter 和 monitorexit 指令
  • Java对象头
    在这里插入图片描述
    synchronized 使用的锁对象是存储在 Java 对象头里的。

Volatile 实现原理

  • 首先了解一下 Java 中线程、工作内存、主内存三者之间的关系
    在这里插入图片描述
  • volatile 的特点:
    1、Java 虚拟机提供的最轻量级的同步机制;
    2、被 volatile 定义:
    <1>保证此变量对所有线程的可见性;
    在这里插入图片描述
    <2>禁止指令重排序优化;

ReentrantLock(可重入锁)

  • 可重入锁特征
    1、可中断响应
    一个正在等待获取的线程被“告知”无须继续等待下去,就可以停止工作了。
    lockInterruptibly();//以可以响应中断的方式加锁
    isHeldByCurrentThread();//获取指示当前哪个线程持有锁
    2、锁限时操作
    tryLock()或者tryLock(long timeout, TimeUtil unit) 进行一次限时的锁等待
    前者不带参数,这时线程尝试获取锁,如果获取到锁则继续执行,如果锁被其他线程持有,则立即返回 false ,也就是不会使当前线程等待,所以不会产生死锁。 后者带有参数,表示在指定时长内获取到锁则继续执行,如果等待指定时长后还没有获取到锁则返回false。
    3、公平锁
    当锁处于无线程占有的状态,在其他线程抢占该锁的时候,都需要先进入队列中等待。
    4、结合 Condition 使用
    AQS 中的 Condition 配合 ReentrantLock 使用,实现了 wait/notify 的功能。

volatile和synchronized的区别:
1、volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
2、volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
3、volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
4、volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
5、volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

Synchronized 和 ReentrantLock 的区别:
1.ReentrantLock功能性方面更全面,比如时间锁等候,可中断锁等候,锁投票等,因此更有扩展性。在多个条件变量和高度竞争锁的地方,用ReentrantLock更合适,ReentrantLock还提供了Condition,对线程的等待和唤醒等操作更加灵活,一个ReentrantLock可以有多个Condition实例,所以更有扩展性。
2.ReentrantLock必须在finally中释放锁,否则后果很严重,编码角度来说使用synchronized更加简单,不容易遗漏或者出错。
3.ReentrantLock 的性能比synchronized会好点。
4.ReentrantLock提供了可轮询的锁请求,他可以尝试的去取得锁,如果取得成功则继续处理,取得不成功,可以等下次运行的时候处理,所以不容易产生死锁,而synchronized则一旦进入锁请求要么成功,要么一直阻塞,所以更容易产生死锁。

猜你喜欢

转载自blog.csdn.net/xyxy66/article/details/82773490
0条评论
添加一条新回复