作用和用法

  • 在多线程对共享资源进行并发访问方面,JDK提供了synchronized关键字来进行线程同步,实现多线程并发访问的线程安全。synchronized的作用主要体现在三个方面:(1)确保线程互斥地访问同步代码;(2)保证共享变量的线程可见性;(3)禁止指令重排。其中(2)和(3)相当于volatile关键字的作用。
  • synchronized可以用在代码的以下地方:

(1)静态方法:将类对象自身作为monitor对象,对该类所有使用了sychronized修饰的静态方法进行同步,即任何时候只能存在一个线程在调用该类的使用了synchronized修饰的静态方法,其他调用了该类的使用了synchronized修饰的静态方法的线程需要阻塞;

(2)普通成员方法:使用类的对象实例作为monitor对象,该类所有使用了synchronized修饰的成员方法,在任何时刻只能被一个线程访问,其他线程需要阻塞;

(3)代码块:使用某个对象作为monitor对象,通常为一个普通的private成员变量,如private Object object = new Object();,这样所有使用了该object对象的同步块,在任何时候只能存在一个线程访问。

  • synchronized可以与monitor对象的wait,notify,notifyAll方法一起来使用,实现线程之间的通信,如实现生产者和消费者模型。其中多个线程共享一个monitor对象,在线程持有synchronized锁时,才能调用monitor的wait,notify或者notifyAll,分别用于释放monitor锁,阻塞休眠,等待其他线程;通知和唤醒其中一个阻塞休眠的线程,让该线程去获取monitor锁;通知所有阻塞休眠的线程去竞争monitor锁。
  • synchronized使用方便,无需显示地在应用代码中加锁和解锁,只需在对应的方法或者代码块中使用synchronized关键字修饰即可,由JVM自身实现自动地加锁和释放锁。
  • synchronized修饰的范围越小,线程并发度越高,性能越好,所以通常使用同步代码块,而不是同步方法来缩小同步范围,优化性能。

实现原理

JVM层面

  • synchronized关键字是基于JVM提供的monitorenter和monitorexit字节码指令,以及结合监视器monitor来实现的。
  • 由上面的分析可知,synchronized关键字用在静态方法,普通成员方法,代码块中,分别需要以类对象自身,类的对象实例,某个普通对象作为对应的monitor对象。
  • 由JVM的相关知识可知,任何java类都需要编译成class字节码,然后加载到JVM当中去执行。而在编译一个java类生成对应class字节码时,当遇到sychronized关键字时,会在sychronized关键字所修饰的方法或者代码块的开始处:增加一个monitorenter字节码指令,在方法或者代码块的结束处:增加monitorexit字节码指令,即使用monitorenter和monitorexit字节码指令包围该方法或者代码块对应的字节码。如下:
  • 在类的成员方法中使用synchronized关键字:
  • 反编译该类对应的class字节码文件:在成员方法method对应的字节码周围使用了monitorenter和monitorexit字节码指令。

monitorenter和monitorexit指令的作用为:

  • monitorenter的作用:所有线程共享该同步代码和该对象关联的监视器monitor,每个线程执行到monitorenter指令的时候,会检查对应的monitor对象的计数是否为0,是则当前线程成为该monitor对象的owner,即锁住该monitor对象了,并递增该计数为1,之后该线程每调用一次使用了该monitor对象进行同步的方法,计数加一(所以synchronized也是可重入的);其他线程检查到monitor对象的计数不为0,则知道该monitor对象已经被其他线程持有锁住了,故当前线程会阻塞直到该monitor的计数重新变为0,则阻塞的线程们会继续竞争成为该monitor的owner,从而可以访问同步代码。
  • monitorexit的作用:当持有该monitor对象的线程每执行完一个同步代码时(如对于成员方法,如果该线程调用了多个使用sychronized修饰的成员方法,则每个方法执行完执行一次monitor减一),将monitor的计数减一,当monitor对象的计数递减到0时,则当前线程不再持有该monitor对象,其他阻塞的线程此时可以竞争成为该monitor的owner,成功的线程可以访问同步代码。
  • 为什么monitor对象的wait,notify,notifyAll需要在synchronized同步代码里面使用呢?首先需要理解以下概念:
  1. 每个对象关联一个监视器monitor;
  2. 每个监视器monitor都有一个该对象的锁(即计数是否为0,为0则说明没有其他线程加锁),一个等待队列和一个同步队列;
  • wait方法:释放对象锁,然后进入等待队列;
  • notify和notifyAll方法:从等待队列被唤醒,放到同步队列去竞争该对象锁;
  • 所以线程在执行wait,notify,notifyAll时需要依赖该监视器monitor,即该线程成为该监视器的owner,从而可以访问synchronized包围的同步代码,这样才能有权访问该监视器对应的对象锁,等待队列和同步队列。

操作系统层面

  • 在操作系统层面,synchronized是基于操作系统的Metux Lock来实现的,而操作系统实现线程之间的切换是需要进行上下文切换的,即从用户态切换到内核态,所以这也是synchronized相对来说成本较高,性能相对较低的原因。

java 同步锁_Java多线程:synchronized同步锁的使用和实现原理相关推荐

  1. java线程钥匙_Java多线程并发编程/锁的理解

    一.前言 最近项目遇到多线程并发的情景(并发抢单&恢复库存并行),代码在正常情况下运行没有什么问题,在高并发压测下会出现:库存超发/总库存与sku库存对不上等各种问题. 在运用了 限流/加锁等 ...

  2. java static 可见性_Java多线程 synchronized与可见性的关系以及可见性问题总结

    作者:七里香的编程之路 出自:OSCHINA 原文:my.oschina.net/u/4098550/blog/4548274 能保证可见性的措施 除了volatile 可以让变量保证可见性外.hap ...

  3. java 多线程的同步问题_java多线程解决同步问题的几种方式,原理和代码

    wait()/notify()方法 await()/signal()方法 BlockingQueue阻塞队列方法 PipedInputStream/PipedOutputStream 阻塞队列的一个简 ...

  4. java线程池_Java多线程并发:线程基本方法+线程池原理+阻塞队列原理技术分享...

    线程基本方法有哪些? 线程相关的基本方法有 wait,notify,notifyAll,sleep,join,yield 等. 线程等待(wait) 调用该方法的线程进入 WAITING 状态,只有等 ...

  5. java中的同步关键字_Java中进程同步问题,锁 和synchronized 关键字的用法

    标签: •对象的锁标志 –每个对象都有一个锁标志 –使用synchronized可与锁标志交互 •synchronized关键字的用法有两种: –synchronized语句 –synchronize ...

  6. java 多线程 串行 加锁_java多线程 synchronized 与lock锁 实现线程安全

    如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样 的,而且其他的变量的值也和预期的是一样的,就是线程安全的. 通过卖火车票的例子 火车站要卖票,我们 ...

  7. java同步通信方式_java多线程同步与通信示例(synchronized方式)

    java多线程同步示例,来自<疯狂java讲义>.通过synchronized,wait(),notify(),notifyAll()实现多线程同步与通信.假设现在系统中有两个线程,这两个 ...

  8. java同步与死锁_Java多线程 - 线程同步与死锁

    一.线程同步 1)模拟多个用户同时从银行账户里面取钱 ● Account 类:银行账户类,里面有一些账户的基本信息,以及操作账户信息的方法 //模拟银行账户 classAccount {private ...

  9. java 多线程同步问题_Java多线程同步问题:一个小Demo完全搞懂

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.一个简单的Demo引发的血案 关于线程同步问题我们从一个 ...

最新文章

  1. 第二十三周微职位elk日志系统
  2. 异常解决(一)-- RuntimeError: expected device cpu but got device cuda:0
  3. Python 标准库 —— uuid(生成唯一 ID)
  4. 物联网软件IoT.js、JerryScript、Smart.js、Calvin介绍
  5. 【IntelliJ】IntelliJ IDEA常用设置及快捷键以及自定义Live templates
  6. 在Payara Server和GlassFish中配置密码
  7. 阿里云HBase发布冷存储特性,助你不改代码,1/3成本轻松搞定冷数据处理
  8. linux用户和组基础
  9. 要不要做独立站系统?做了有什么用?
  10. 项目常用工具类整理(二)--ckeditor的引用
  11. 通用数据库连接工具--DbVisualizer的使用
  12. 小凡模拟器(DynamipsGUI)打不开的简单解决方法
  13. 安装RHEL 7(Centos7类同)
  14. 电大本科计算机科学与技术,中央电大开放本科计算机科学与技术专业微计算机技术试题_0701...
  15. 2022.9.13 手机验证码登录功能
  16. android平板 视频输入,安卓平板电脑的新突破口:HDMI in 视频输入,取代便携显示器...
  17. uni-app 170邀请加入群聊(二)
  18. unity课设小游戏_unity3d游戏课程设计报告
  19. 微信小程序之window
  20. 数据库领域中最常用的逻辑模型有哪些?请比较各种模型的优缺点并详述。

热门文章

  1. CGLib动态代理原理
  2. 数据字典在sga的哪一个组件中缓存_【赵强老师】Oracle数据库的内存结构
  3. java string类的方法_Java-String类的常用方法总结
  4. Fail-fast 和 Fail-safe 机制
  5. 抓球球的机器人应该怎么玩_王者荣耀:在游戏中当自己优势队友劣势的时候应该怎么玩?...
  6. 计算机IP为什么只有255,为什么电脑IP地址最大值是255?
  7. Android Studio无线连接设备调试,比数据线更方便
  8. MySql主从同步最小配置
  9. html加动画不改变高度,怎么为不定高度(height:auto)的元素添加CSS3 transition-property:height 动画...
  10. ios html gif 显示,显示gif时出现巨大的内存使用Swift iOS