关键词:
基础概念
synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时可以保证共享变量对内存可见性。
Java中每一个对象都可以作为锁,这是synchronized实现同步的基础:
- 普通同步方法,锁是当前实例对象
- 静态同步方法,锁是当前类的class对象
- 同步方法块,锁是括号里面的对象
当一个线程访问同步代码块时,它首先是需要得到锁才能执行同步代码,当退出或者抛出异常时必须要释放锁。
底层实现
如何来实现这个机制呢?我们先看如下一段简单代码:
public class SynchronizedTest{ public synchronized void test1(){ } public void test2(){ synchronized(this){ } } public static void main(String []args){ } }
利用javap工具查看生成的class 文件信息来分析synchronize的实现
从上图可以看出,同步代码块是使用monitorenter和monitorexit指令实现的,同步方法(在这看不出来需要看JVM底层实现)依靠的是方法修饰符上的ACC_SYNCHRONIZED实现。
在java语言中存在两种内建的synchronized语法:1、synchronized语句;2、synchronized方法。对于synchronized语句当Java源代码被javac编译成bytecode的时候,会在同步块的入口位置和退出位置分别插入monitorenter和monitorexit字节码指令。而synchronized方法则会被翻译成普通的方法调用和返回指令如:invokevirtual、areturn指令,在VM字节码层面并没有任何特别的指令来实现被synchronized修饰的方法,而是在Class文件的方法表中将该方法的access_flags字段中的synchronized标志位置1,表示该方法是同步方法并使用调用该方法的对象或该方法所属的Class在JVM的内部对象表示Klass做为锁对象。
Java synchronized 包含两方面的含义
互斥
JVM 通过对象锁来实现互斥:
typedef struct object { uintptr_t lock; Class *class; } Object
协作
协作是通过 Object wait, notify/notifyAll 方法实现的。
对应到JVM 的底层术语,这一机制叫做 monitor:
typedef struct monitor { pthread_mutex_t lock; Thread *owner; Object *obj; int count; int in_wait; uintptr_t entering; int wait_count; Thread *wait_set; struct monitor *next; } Monitor;
在底层,进行获取 lock 动作到获得 lock 之间有一小段状态叫做 BLOCKED:
void monitorLock(Monitor *mon, Thread *self) { if(mon->owner == self) mon->count++; else { if(pthread_mutex_trylock(&mon->lock)) { disableSuspend(self); self->blocked_mon = mon; self->blocked_count++; self->state = BLOCKED; pthread_mutex_lock(&mon->lock); self->state = RUNNING; self->blocked_mon = NULL; enableSuspend(self); } mon->owner = self; } }
下面我们来了解两个重要的概念:Java对象头,Monitor。
对象头(Object Header):
在JVM中创建对象时会在对象前面加上两个字大小的对象头,在32位机器上一个字为32bit,根据不同的状态位Mark World中存放不同的内容,如上图所示在轻量级锁中,Mark Word被分成两部分,刚开始时LockWord为被设置为HashCode、最低三位表示LockWord所处的状态,初始状态为001表示无锁状态。Klass ptr指向Class字节码在虚拟机内部的对象表示的地址。Fields表示连续的对象实例字段。
Monitor Record:
Monitor Record是线程私有的数据结构,每一个线程都有一个可用monitor record列表,同时还有一个全局的可用列表;那么这些monitor record有什么用呢?每一个被锁住的对象都会和一个monitor record关联(对象头中的LockWord指向monitor record的起始地址,由于这个地址是8byte对齐的所以LockWord的最低三位可以用来作为状态位),同时monitor record中有一个Owner字段存放拥有该锁的线程的唯一标识,表示该锁被这个线程占用。如下图所示为Monitor Record的内部结构:
Owner:初始时为NULL表示当前没有任何线程拥有该monitor record,当线程成功拥有该锁后保存线程唯一标识,当锁被释放时又设置为NULL;
EntryQ:关联一个系统互斥锁(semaphore),阻塞所有试图锁住monitor record失败的线程。
RcThis:表示blocked或waiting在该monitor record上的所有线程的个数。
Nest:用来实现重入锁的计数。
HashCode:保存从对象头拷贝过来的HashCode值(可能还包含GC age)。
Candidate:用来避免不必要的阻塞或等待线程唤醒,因为每一次只有一个线程能够成功拥有锁,如果每次前一个释放锁的线程唤醒所有正在阻塞或等待的线程,会引起不必要的上下文切换(从阻塞到就绪然后因为竞争锁失败又被阻塞)从而导致性能严重下降。Candidate只有两种可能的值0表示没有需要唤醒的线程1表示要唤醒一个继任线程来竞争锁。
深入分析volatile的实现原理
引言在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改... 查看详情
java并发深入分析volatile的实现原理
通过前面一章我们了解了synchronized是一个重量级的锁,虽然JVM对它做了很多优化,而下面介绍的volatile则是轻量级的synchronized。如果一个变量使用volatile,则它比使用synchronized的成本更加低,因为它不会引起线程上下文的切换和... 查看详情
聊聊并发深入分析volatile的实现原理
...ww.infoq.com/cn/articles/ftf-java-volatile引言在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性”。可见性的意思是当一个线程修改一个共享变量时... 查看详情
深入理解多线程——synchronized的实现原理(代码片段)
synchronized,是Java中用于解决并发情况下数据同步访问的一个很重要的关键字。当我们想要保证一个共享资源在同一时间只会被一个线程访问到时,我们可以在代码中使用synchronized关键字对类或者对象加锁。那么,本文来介绍一... 查看详情
深入理解synchronize(代码片段)
本文参考引用,本人整理个人理解。地址点击1.实现原理synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性。下面是一些同步的基础普通同步方法,... 查看详情
深入理解多线程——moniter的实现原理(代码片段)
...文,阅读该系列所有文章。在深入理解多线程(一)——Synchronized的实现原理中介绍过关于Synchronize的实现原理,无论是同步方法还是同步代码块,无论是AC 查看详情
java并发编程专题系列之深入分析synchronized(基础篇)
synchronized同步关键字简介synchronized是属于JVM层面的一个关键字,底层是通过一个monitor对象(管程对象)来完成,由于wait()/notify()等方法也依赖于monitor对象,所以只有在同步的块或者方法中才能调用wait/notify等方法synchronized同步代码... 查看详情
synchronized实现原理(代码片段)
记得刚刚开始学习Java的时候,一遇到多线程情况就是synchronized。对于当时的我们来说,synchronized是如此的神奇且强大。我们赋予它一个名字“同步”,也成为我们解决多线程情况的良药,百试不爽。但是,随着学习的深入,我... 查看详情
深入hotspot虚拟机源码探究synchronized底层实现原理万字总结synchronized(代码片段)
文章目录一、synchronized原理(1)首先准备好HotSpot源码(2)解压,使用vscode或者其他编辑器打开(3)初始monitor监视器锁(先了解后细说)(4)建立宏观概念(初始基本流程)... 查看详情
深入理解synchronized底层原理,一篇文章就够了!(代码片段)
...资源数据错乱,我们需要对线程进行同步,那么synchronized就是实现线程同步的关键字,可以说在并发控制中是必不可少的部分,今天就来看一下synchronized的使用和底层原理。synchronized的特性原子性所谓原子性就是... 查看详情
synchronized的实现原理及锁优化(代码片段)
... 记得刚刚开始学习Java的时候,一遇到多线程情况就是synchronized。对于当时的我们来说,synchronized是如此的神奇且强大。我们赋予它一个名字“同步”,也成为我们解决多线程情况的良药,百试不爽。但是,随着学习的深入,... 查看详情
011深入理解synchronized(代码片段)
一.概述在前面我们使用synchronized完成了一个原子方法的实现.现在我们需要深入的理解这个关键词. 二.使用方式 对于这个关键词我们的使用方式有四种: [1]修饰普通方法 [2]修饰静态方法 [3]对实例对象加互斥锁... 查看详情
semaphore实现原理分析
synchronized的语义是互斥锁,就是在同一时刻,只有一个线程能获得执行代码的锁。但是现实生活中,有好多的场景,锁不止一把。比如说,又到了十一假期,买票是重点,必须圈起来。在购票大厅里,有5个售票窗口,也就是说... 查看详情
深入分析zookeeper的实现原理
zookeeper的由来 分布式系统的很多难题,都是由于缺少协调机制造成的。在分布式协调这块做得比较好的,有Google的Chubby以及Apache的Zookeeper。GoogleChubby是一个分布式锁服务,通过Google Chubby来解决分布式协作、Master选举等与... 查看详情
reentrantlock实现原理及源码分析
...k是Java并发包中提供的一个可重入的互斥锁。ReentrantLock和synchronized在基本用法,行为语义上都是类似的,同样都具有可重入性。只不过相比原生的Synchronized,ReentrantLock增加了一些高级的扩展功能,比如它可以实现公平锁,同时... 查看详情
深入分析object.finalize方法的实现原理
“物有本末,事有始终。知其先后,则近道矣”finalize如果类中重写了finalize方法,当该类对象被回收时,finalize方法有可能会被触发,下面通过一个例子说明finalize方法对垃圾回收有什么影响。publicclassFinalizeCase{privatestaticB... 查看详情
synchronize底层实现原理(代码片段)
????相信对Java程序员来说,synchronized关键字对大家来说并不陌生,当我们遇到并发情况时,优先会想到用synchronized关键字去解决,synchronized确实能够帮助我们去解决并发的问题,但是它会引起一些其他问题,比如最突出的一点就... 查看详情
深入分析java线程池的实现原理
前言线程是稀缺资源,如果被无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,合理的使用线程池对线程进行统一分配、调优和监控,有以下好处:1、降低资源消耗;2、提高响应速度;3、提高线程的可管理性。Jav... 查看详情