synchronized的三种应用方式

一. 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁。

二. 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁。

三. 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象。

synchronized的字节码指令

  synchronized同步块使用了monitorenter和monitorexit指令实现同步,这两个指令,本质上都是对一个对象的监视器(monitor)进行获取,这个过程是排他的,也就是说同一时刻只能有一个线程获取到由synchronized所保护对象的监视器。

  线程执行到monitorenter指令时,会尝试获取对象所对应的monitor所有权,也就是尝试获取对象的锁,而执行monitorexit,就是释放monitor的所有权。

synchronized的锁的原理

  两个重要的概念:一个是对象头,另一个是monitor。

Java对象头

  在Hotspot虚拟机中,对象在内存中的布局分为三块区域:对象头(Mark Word、Class Metadata Address)、实例数据和对齐填充;Java对象头是实现synchronized的锁对象的基础。一般而言,synchronized使用的锁对象是存储在Java对象头里。它是轻量级锁和偏向锁的关键。

Mark Word

  Mark Word用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的
锁、偏向线程 ID、偏向时间戳等等。Java对象头一般占有两个机器码(在32位虚拟机中,1个机器码等于4字节,
也就是32bit)。

Class Metadata Address

  类型指针,即是对象指向它的类的元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

Array length

如果对象是一个Java数组,那在对象头中还必须有一块用于记录数组长度的数据。

Monitor

  Monitor是一个同步工具,它内置于每一个Object对象中,相当于一个许可证。拿到许可证即可以进行操作,没有拿到则需要阻塞等待。

  在hotspot虚拟机中,通过ObjectMonitor类来实现monitor。

synchronized锁的优化

  jdk1.6以后对synchronized的锁进行了优化,引入了偏向锁、轻量级锁,锁的级别从低到高逐步升级:

  无锁->偏向锁->轻量级锁->重量级锁

自旋锁与自适应自旋

  线程的挂起和恢复会极大的影响开销。并且jdk官方人员发现,很多线程在等待锁的时候,在很短的一段时间就获得了锁,所以它们在线程等待的时候,并不需要把线程挂起,而是让他无目的的循环,一般设置10次。这样就避免了线程切换的开销,极大的提升了性能。

而适应性自旋,是赋予了自旋一种学习能力,它并不固定自旋10次一下。他可以根据它前面线程的自旋情况,从而调整它的自旋,甚至是不经过自旋而直接挂起。

锁消除

  对不会存在线程安全的锁进行消除。

锁粗化

  如果jvm检测到有一串零碎的操作都对同一个对象加锁,将会把锁粗化到整个操作外部,如循环体。

偏向锁

  多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让其获得锁的代价更低而引入了偏向锁。

  当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁,只需简单地测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。

  如果测试成功,表示线程已经获得了锁。

  如果测试失败,则需要再测试一下Mark Word中偏向锁的标识是否设置成01(表示当前是偏向锁)。

  如果没有设置,则使用CAS竞争锁。

  如果设置了,则尝试使用CAS将对象头的偏向锁指向当前线程。

轻量级锁

  引入轻量级锁的主要目的是在多线程竞争不激烈的情况下,通过CAS竞争锁,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。

重量级锁

  重量级锁通过对象内部的监视器(monitor)实现,其中monitor的本质是依赖于底层操作系统的Mutex Lock实现,操作系统实现线程之间的切换需要从用户态到内核态的切换,切换成本非常高。

锁升级

  偏向锁升级轻量级锁:当一个对象持有偏向锁,一旦第二个线程访问这个对象,如果产生竞争,偏向锁升级为轻量级锁。

  轻量级锁升级重量级锁:一般两个线程对于同一个锁的操作都会错开,或者说稍微等待一下(自旋),另一个线程就会释放锁。但是当自旋超过一定的次数,或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁膨胀为重量级锁,重量级锁使除了拥有锁的线程以外的线程都阻塞,防止CPU空转。

wait和notify的原理

  调用wait方法,首先会获取监视器锁,获得成功以后,会让当前线程进入等待状态进入等待队列并且释放锁。

  当其他线程调用notify后,会选择从等待队列中唤醒任意一个线程,而执行完notify方法以后,并不会立马唤醒线程,原因是当前的线程仍然持有这把锁,处于等待状态的线程无法获得锁。必须要等到当前的线程执行完按monitorexit指令以后,也就是锁被释放以后,处于等待队列中的线程就可以开始竞争锁了。

wait和notify为什么需要在synchronized里面?

  wait方法的语义有两个,一个是释放当前的对象锁、另一个是使得当前线程进入阻塞队列,而这些操作都和监视器是相关的,所以wait必须要获得一个监视器锁。

而对于notify来说也是一样,它是唤醒一个线程,既然要去唤醒,首先得知道它在哪里,所以就必须要找到这个对象获取到这个对象的锁,然后到这个对象的等待队列中去唤醒一个线程。

转载于:https://www.cnblogs.com/heqiyoujing/p/11144649.html

synchronize原理相关推荐

  1. 暴力突破 Java 并发 - synchronize 解析

    一.前言 当存在多个线程操作共享数据时,需要保证同一时刻有且只有一个线程在操作共享数据,其他线程必须等到该线程处理完数据后再进行,这种方式有个高尚的名称叫互斥锁,即能达到互斥访问目的的锁,也就是说当一 ...

  2. 大厂Java岗面试心得记录

    最近裸辞,面了几家大厂,offer率高达100% 哈哈,然后发现选公司也是一件难事. 废话不多说,分享一下,我遇到的面试题,大概有以下这些: JVM: 1.JVM有哪些区域? 2.堆和栈分别说说内部东 ...

  3. 应该是史上最全最新Java和Android面试题目(自己总结和收集的)

    Android面试题目 Java 基础 int占用几个字节 讲一下常见编码方式? UTF-8编码下中文占几个字节 int和Interger的区别 int.char.long各占多少字节数 string ...

  4. Android最新面试实战总结

    热文导读 | 点击标题阅读 金九银十跳槽季如何进阶找到合适满意的工作? Spring中的9种设计模式汇总 凛冬将至?对互联网行业人员流动性的一些看法(深度好文) 作者:骑小猪看流星 来源:http:/ ...

  5. 枪出惊龙,众“锁”周之

    枪出惊龙,众"锁"周之 1.为什么要上锁?锁的意义是什么? 1 多线程访问共享数据,保证数据的安全 2 他会降低并发量,但是他能保证数据的安全 问题:秒杀本来是高并发的场景,你加锁 ...

  6. JAVA多线程之Synchronize 关键字原理

    image 众所周知 Synchronize 关键字是解决并发问题常用解决方案,有以下三种使用方式: 同步普通方法,锁的是当前对象. 同步静态方法,锁的是当前 Class 对象. 同步块,锁的是 {} ...

  7. 大话synchronize底层原理

    在每个对象中mark word中LockWord指向monitor的起始地址,也就是每个对象与一个monitor相关联.在monitor中有个Owner字段记录着拥有锁的线程.初始时为NULL表示当前 ...

  8. synchronize底层原理

    1.对象内存布局 2.markword内容 3.锁状态图 4.轻量级锁 如果只有当前线程给对象加锁,则使用轻量级锁.(ps:没有其他线程和当前线程竞争,竞争就是两个线程同时给一个对象加锁) 加锁过程: ...

  9. 计算机共享原理,synchronize底层原理 游戏电脑问题解决分享!

    sync 1 package com.paddx.test.concurrent; 2 3 public class SynchronizedDemo { 4 public void method() ...

最新文章

  1. Eclipse 官宣,干掉 VS Code !
  2. PHP 入门 - 7.Web技术
  3. 计算机专业英语第二版张强华翻译_计算机语言发展的三个阶段,机器语言、汇编语言与高级语言...
  4. mui toast自定义样式
  5. java 易错题_java错题集(1-3)
  6. 拓端tecdat|R语言用普通最小二乘OLS,广义相加模型GAM ,样条函数进行逻辑回归LOGISTIC分类
  7. sqlserver替换特殊字符
  8. 下载谷歌瓦片地图并拼接为高清大图
  9. 教你利用腾讯云cdn加速网站静态资源
  10. matlab的卡方临界值,Excel计算卡方分布,F分布
  11. matlab中单刀双掷开关,proteus 怎样找单刀双掷开关
  12. 我是80后程序员,我支持正版!
  13. 如何在国内快速访问Github
  14. Web程序中打开QQ、邮箱、阿里旺旺等
  15. Java数据可视化 (JavaFX, Apache ECharts)
  16. 全网通用Python点赞器(俗称刷分机器),想知道原理吗?看完本文你自己也能写个
  17. 发展科技到底有什么用,转NASA专家给一位修女的一封信
  18. 2020研究生数模竞赛思路
  19. python在西安好找工作吗_为什么我不建议你通过 Python 去找工作?
  20. 佟大为新任《非诚》嘉宾 极力反对异地恋

热门文章

  1. mysql 存储引擎接口_MySQL 的基础一(连接池, SQL接口, 查询解析器, 查询优化器, 存储引擎接口, 执行器,)...
  2. 有关EMMC、Nandflash、SSD、HDD的科普类说明
  3. head在linux命令中什么意思,linux系统中head命令使用说明
  4. bat php 监控网站,bat curl 发送http请求 监控网站
  5. 语句作用_3分钟短文:Laravel模型作用域,为你“节省”更多代码
  6. c语言试卷大全,C语言试题大全
  7. 日志分析系统分类有哪些_Java开发日志规范
  8. Linux 系统配置Java Idea Tomcat 全过程
  9. 数学--数论--HDU 2582 F(N) 暴力打表找规律
  10. 康美药业财务造假给股民造成的损失,股民该怎么办?