Synchronized
- 在java中synchronized关键词具有使每个线程依次排队操作共享变量的功能。
一、Synchronized使用
- 当锁住的是实例对象,它是作用于该实例的范围,其它不同的实例对象仍然可以执行。
- 当锁住的是类对象,他是作用于某个类的范围,只要是该类的实例对象都会受到影响。

二、Synchronized原理
当使用了synchronized,会在生成的class信息中出现下面两种情况:
(1)同步代码块使用了monitorenter和monitorexit指令实现。
代码:

class信息中:

(2)同步方法中依靠方法修饰符上ACC_SYNCHRONIZED实现。
代码:
![]()
class信息中:

备注:
1)Synchronized的自旋是怎么实现的?代码如何实现
在Java中,synchronized关键字的底层实现确实涉及自旋优化,但这一过程是由JVM自动管理的,开发者无需手动编写自旋代码。以下是其实现原理及代码示例:
synchronized自旋的实现原理:
1-1)锁升级机制:
- 偏向锁:首次访问时标记线程ID,无竞争时直接进入。
- 轻量级锁(自旋锁):当发生轻微竞争时,线程通过CAS自旋尝试获取锁。
- 重量级锁:自旋失败后,锁升级为操作系统级别的互斥锁,线程进入阻塞状态。
1-2)自旋的实现:
- 轻量级锁阶段,JVM会让未获取锁的线程执行忙循环(自旋),通过CAS(Compare-And-Swap)操作不断检查锁状态。
- CAS通过硬件指令(如x86的
cmpxchg)保证原子性,确保只有一个线程能成功修改锁标志。
1-3)自适应自旋优化:
- JVM会根据锁的历史状态动态调整自旋次数(如之前自旋成功则允许更长时间的自旋)。
2)Wait/notify/notifyAll方法需不需要被包含在synchronized块中?这是为什么
在Java中,wait()、notify()和notifyAll()方法必须被包含在synchronized块或同步方法中,否则会抛出IllegalMonitorStateException异常。
2-1)锁的持有是前提条件
wait()和notify()的语义要求线程必须 先持有对象的监视器锁(Monitor Lock)才能调用这些方法。- 直接原因:若未持有锁,调用这些方法会触发
IllegalMonitorStateException。 - 底层逻辑:这些方法依赖锁机制实现线程间协作,锁的存在保证了线程对共享资源的安全访问。
2-2)保证操作的原子性
wait()方法会释放当前锁并让线程进入等待状态,而notify()会唤醒其他等待线程。- 这两个操作必须在一个原子步骤中完成,否则可能导致:
-
- 竞态条件(Race Condition):例如,线程A调用
notify()后,线程B尚未进入等待状态,导致通知丢失。 - 数据不一致:共享资源的状态可能在未同步的情况下被意外修改。
- 竞态条件(Race Condition):例如,线程A调用
2-3)内存可见性
synchronized块不仅提供互斥,还确保内存可见性(通过happens-before规则)。- 若不在同步块中调用
wait()或notify(),线程可能无法感知其他线程对共享变量的修改(如缓存不一致问题)。
更多java基础总结(适合于java基础学习、java面试常规题):
总结篇(9)---字符串及基本类 (1)字符串及基本类之基本数据类型
总结篇(10)---字符串及基本类 (2)字符串及基本类之java中公共方法及操作
总结篇(12)---字符串及基本类 (4)Integer对象
总结篇(14)---JVM(java虚拟机) (1)JVM虚拟机概括
总结篇(15)---JVM(java虚拟机) (2)类加载器
总结篇(16)---JVM(java虚拟机) (3)运行时数据区
总结篇(17)---JVM(java虚拟机) (4)垃圾回收
总结篇(18)---JVM(java虚拟机) (5)垃圾回收算法
总结篇(19)---JVM(java虚拟机) (6)JVM调优
总结篇(24)---Java线程及其相关(2)多线程及其问题
总结篇(25)---Java线程及其相关(3)线程池及其问题
总结篇(26)---Java线程及其相关(4)ThreadLocal
总结篇(27)---Java并发及锁(1)Synchronized
总结篇(31)---JUC工具类(1)CountDownLatch
本文详细介绍了Java中的synchronized关键字,解释了其如何实现线程间的同步操作,并探讨了它在实例对象与类对象上的不同作用范围。同时,文章还介绍了synchronized在字节码层面的具体实现方式。

被折叠的 条评论
为什么被折叠?



