- 首先说下其使用特点:
- 排他:一个对象的锁只在一个时间段内,只能被一个线程持有,其它企图持有锁的线程都处于blocked状态(或是自旋状态running)
-
非公平:不是先申请就能先得到锁(jdk1.5后,ReentrantLock可以代替synchronized,可选择公平还是非公平,不过公平锁的吞吐量要低很多,数倍,ReentrantLock的效率不一定更高,但是代码会更易读)
- 内部:
先介绍下对象头信息,JVM里面每个对象都有一个对象头,普通对象两个字,数组3个字(字长为虚拟机位数,32、64)
长度 | 内容 | 说明 |
字(32/64) | Mark Word | 存储对象的hashcode,分代年龄,锁信息 |
字(32/64) | Class Metadata Address | 对象的类对象的指针 |
字(32/64) | Array Length | 数组长度(如果是数组的话) |
在本主题只介绍Mark Word内容,32位jvm如下:
64位如下:
-
偏向锁(Biased):
场景,某线程获得锁之后,为了消除此线程锁重入的开销(CAS),就像此线程得到了偏袒。
对象A,线程T,T竞争A上的锁,动作如下:
先检查,发现对象A处于初始状态(Tag为01,偏向信息为0),可以加偏向锁;
如果A上已经有偏向信息(注意,不是锁,这意味着现在就有或是曾经加过偏向锁,Tag为01,偏向信息为1,Thread Id为T),T也就是当前线程嘛,那就是重入,啥也不用做,继续操作;如果不是当前线程,那就是有不同线程竞争锁,那就要将偏向锁撤销(revode)为轻量锁,再升级为自旋-->重量锁。这个撤销操作,稍后介绍。
这就是加偏向锁的条件及过程,若是其它情况偏向锁都不会启用。
重入:发现有偏向锁,检查threadid是否就是当前线程,是,那么重入成功。解锁:要等到非本线程竞争者出现,才会撤销。(意思是,就算同步块已经完成,mark value也不会恢复未加锁状态)
总结:在没有不同线程加锁的情况下,重入开销小(cas操作都不需要),解锁是被动的(开销也小),但是一旦换个线程来竞争锁,就得-->轻量锁-->自旋-->重量。
-
轻量锁(Light-weight):
场景:线程T1曾经获取了对象A上的锁(最初就是偏向锁,当然也可能是轻量锁),然后释放了,线程T2尝试获取A上的锁,此时轻量锁就派上用场了。
先判断A的Mark Value的内容,无锁,或是曾经有偏向锁;
T2的栈里面会新生成一个lock record对象,其内容就是A的Mark Value的copy;
通过CAS操作,将A的MarkValue设为lock record地址,将tag设为00,如果成功,那么就获取锁成功;失败,那说明已经有别的线程已经先一步获A上的锁了,那么就要升级到自旋或是重量锁。
重入:也就是判断A的Mark Value时,发现有轻量锁,其地址指向的lock record就在T2的栈内,每一次重入,都会在T2的栈上新生成一个lock record,过程和新上锁一样,实际上就形成了一个版本队列,栈上第一个lock record保存的内容是第一次获取A的锁的时候的内容(无锁,或是曾经有偏向锁),第二个lock record保存的就是第一次获取锁之后A上Mark Value的内容。。。
解锁:通过CAS操作将T2栈上的lock record还原到A的Mark Value中,如果操作成功,那么解锁成功,失败则说明有别的线程在竞争A上的锁,已经升级为自旋或是重量锁了。
总结:在没有多线程竞争的情况下,首次加锁或重入加锁的开销都差不多,一个CAS操作,但是一旦出现多线程竞争,就往自旋或是重量锁转变。 -
自适应自旋锁:
任务本身要做的事如果很短,比如就是个计数器,这时如果使用阻塞锁,那么切换线程的开销可能比任务本身还大。
自旋就是为了优化这个问题,让线程执行一个无意义循环来竞争锁,如果竞争不到,继续循环(而不是线程阻塞),直到获取锁,或是达到某一个基于统计的次数(基于JVM运行时的统计,这个次数称为上界,这就是自适应)而仍然没有拿到锁,那就转换为阻塞锁。此过程中线程一直处于RUNNABLE状态,直到任务完成或是转换成阻塞锁,转换为阻塞锁,线程就处于BLOCKED状态。
可以抽象的解释为:线程会先不断尝试竞争锁(有次数限制,上界),超过次数,那么说明资源很紧俏,别老嚷嚷了,认命吧,进入阻塞状态安心等待。
好处:不用第一次失败就进入阻塞队列(可能没有队列,空间优化),失败一定次数了,那么说明资源很紧俏,别老嚷嚷了,嚷嚷也要口水的,不如等资源管理者给你分配更有效(时间优化)。
-
阻塞锁(重量锁,Monitor):
线程竞争锁的时候先尝试一把,如果失败或是锁已经被拿走,那么线程进入BLOCKED状态,并被塞入阻塞队列。等到锁释放,队列中的锁又来打一次群架,成功的做事,失败的老实呆着。
具体的可以参考另外一篇:http://blog.csdn.net/chen77716/article/details/6618779线程的阻塞和唤醒需要CPU从用户态转为核心态,频繁切换的开销还是挺大的。
-
待续
相关推荐
"Java 中 synchronized 用法详解" Synchronized 是 Java 语言中用于解决多线程共享数据同步问题的关键字。它可以作为函数的修饰符,也可以作为函数内的语句,用于实现同步方法和同步语句块。在 Java 中,...
你还在用synchronized?线程安全相关知识深入剖析
synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果 再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class ...
java锁机制Synchronized java锁机制Synchronized java锁机制Synchronized java锁机制Synchronized
java synchronized的一些小实验,对帮助理解synchronized的使用有一定的帮助。
java里面synchronized用法
Synchronized锁在Spring事务管理下,导致线程不安全。
synchronized的几种示例研究,方法加锁,代码块加锁(this和对象)以及静态方法加锁的示例和效果。基本上包含了synchronized的几种常用的方式。
java多线程中synchronized关键字的用法 解压密码 www.jiangyea.com
This document specifies the third version of the Synchronized Multimedia Integration Language (SMIL, pronounced "smile"). SMIL 3.0 has the following design goals: ● Define an XML-based language...
volatile与synchronized的区别,锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility)
synchronized 测试案例,同步一个对象或者多个对象的案例均有,还有成功和失败案例的对比
我自己的博客所附带的案例源码,我的博客标题名称是"synchronized并发讲解",关注我等待跟多更新
有需要2014版本之前的Synchronized 6-Pulse Generator元器件,提供slx文件下载,直接复制过去即可使用。Matlab表示:如果您的旧版型号包含 同步6脉冲发生器模块,它们将继续工作。但是,为获得最佳性能,请在新型号...
java同步synchronized关键字用法示例
java多线程编程核心技术synchronized实例大全,同步方法,同步语句块,类锁,对象锁全都用代码来展现出来
Synchronized关键字的用法
java中synchronized的使用,java中的锁锁的到底是什么?是括号里的代码块吗?肯定不是的;
synchronized关键字在java中的重要性 以及常用的方法 还有它的详解
java语言 并发编程 ReentrantLock与synchronized区别 详解