谈一谈synchronized关键词
1.使用
java中的每一个对象都可以作为synchronized的锁进行代码同步,常见的形式
- 同步代码块锁是synchronized括号内的对象
- 普通成员方法上,锁是当前的对象,synchronized(this)
- 静态方法上,锁是当前类的Class对象
2. 原理
synchronized是通过指定某个对象进行加锁,那么synchronized的锁信息肯定是和对象有关。Java的对象头里的Mark Word字段,默认是存储对象的HashCode。32位虚拟机中Mark Word的存储结构
| 锁状态 | Mark Word中的存储内容 | 标志位 |
|---|---|---|
| 无锁状态 | Hash code,偏向锁0 | 01 |
| 偏向锁 | 线程ID,偏向锁1 | 01 |
| 轻量级锁 | 指向栈中锁记录的指针 | 00 |
| 重量级锁 | 指向互斥量的指针 | 10 |
3.锁升级
偏向锁 ==> 轻量级锁 ==> 重量级锁
锁只能升级、不能退化
1.偏向锁
- 偏向锁加锁:Mark Word中记录了当前获取锁线程ID,这样同一个线程可以多次进入同一个共享代码块而无需加锁。如果是无锁状态,则尝试通过CAS将偏向锁中的线程id修改为当前线程。
- 偏向锁解锁:需要等到全局安全点(在这个时间点上没有正在执行的字节码)会首先暂停拥有偏向锁的线程,判断锁对象是否处于被活动状态,撤销偏向锁后恢复到未锁定或升级为轻量级锁。
2.轻量级锁
- 加锁:在栈帧中创建空间(Displaced Mark Word)存储Mark Word中内容,然后尝试使用Cas把Mark word中的指针指向栈帧。成功则获取锁,失败则通过自旋获取锁,自旋失败则升级为重量级锁
- 解锁:通过CAS把栈帧中的(Displaced Mark Word使用CAS替换回Mark Word,成功则说明在期间没有锁竞争,否则唤醒等待线程(已经升级为重量级锁)
3.锁的优缺点
| 锁 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 偏向锁 | 加锁和解锁不需要额外的消耗,和执行非同步方法比仅存在纳秒级的差距 | 如果线程间存在锁竞争,会带来额外的锁撤销的消耗 | 适用于只有一个线程访问同步块场景 |
| 轻量级锁 | 竞争的线程不会阻塞,提高了程序的响应速度 | 如果始终得不到锁竞争的线程使用自旋会消耗CPU | 追求响应时间,锁占用时间很短 |
| 重量级锁 | 线程竞争不使用自旋,不会消耗CPU | 线程阻塞,响应时间缓慢 | 追求吞吐量,锁占用时间较长 |
4. StringBuilder和StringBuffer
如果你看到别人在非并发环境下使用StringBuffer就说,你这里应该用StringBuilder啊,用StringBuffer明显影响性能。这句话前面半句是没问题的,但是说明显影响性能这个就有点显得不那么专业了。如果你看明白的了synchronized的锁升级就应该知道,在单线程环境下永远是偏向锁,不会升级。因此性能开销可以忽略不计。
As of release JDK 5, this class has been supplemented with an equivalent
class designed for use by a single thread, link StringBuilder. The
StringBuilder class should generally be used in preference to
this one, as it supports all of the same operations but it is faster, as
t performs no synchronization.
5. synchronized + String
public class TTT {
public static void main(String[] args) throws ParseException, InterruptedException {
new MyThread("A").start();
synchronized (new String("B")) {
new MyThread("B").start();
}
new MyThread("A").start();
}
public static void synchronizeMethod(String str) throws InterruptedException {
synchronized (str) {
TimeUnit.SECONDS.sleep(2);
System.out.println(str);
}
}
static class MyThread extends Thread {
String str;
public MyThread(String str) {
this.str = str;
}
@Override
public void run() {
try {
synchronizeMethod(str);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
你知道上面代码的执行情况吗。如果不明白那说明synchronized使用和String的内存分配情况还有欠缺。
谈一谈synchronized关键词的更多相关文章
- 谈一谈Java8的函数式编程(二) --Java8中的流
流与集合 众所周知,日常开发与操作中涉及到集合的操作相当频繁,而java中对于集合的操作又是相当麻烦.这里你可能就有疑问了,我感觉平常开发的时候操作集合时不麻烦呀?那下面我们从一个例子说起. 计 ...
- 谈一谈泛型(Generic)
谈一谈泛型 首先,泛型是C#2出现的.这也是C#2一个重要的新特性.泛型的好处之一就是在编译时执行更多的检查. 泛型类型和类型参数 泛型的两种形式:泛型类型( 包括类.接口.委托和结构 没有泛型枚 ...
- 从一张图开始,谈一谈.NET Core和前后端技术的演进之路
从一张图开始,谈一谈.NET Core和前后端技术的演进之路 邹溪源,李文强,来自长沙.NET技术社区 一张图 2019年3月10日,在长沙.NET 技术社区组织的技术沙龙<.NET Core和 ...
- 谈一谈Elasticsearch的集群部署
Elasticsearch天生就支持分布式部署,通过集群部署可以提高系统的可用性.本文重点谈一谈Elasticsearch的集群节点相关问题,搞清楚这些是进行Elasticsearch集群部署和拓 ...
- 谈一谈iOS事件的产生和传递
谈一谈iOS事件的产生和传递 1.事件的产生 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中. UIApplication会从事件队列中取出最前面的事件,并将事件 ...
- Java多线程系列3 synchronized 关键词
先来看一个线程安全的例子 ,两个线程对count进行累加,共累加10万次. public class AddTest { public static void main(String[] args) ...
- 谈一谈对MySQL InnoDB的认识及数据库事物处理的隔离级别
介绍: InnoDB引擎是MySQL数据库的一个重要的存储引擎,和其他存储引擎相比,InnoDB引擎的优点是支持兼容ACID的事务(类似于PostgreSQL),以及参数完整性(有外键)等.现在Inn ...
- 谈一谈APP版本号问题
如题:谈一谈APP版本号问题 为什么要谈这个问题,周五晚上11~12点,被微信点名,说APP有错,无效的版本号,商城无法下单.我正在准备收拾东西,周末回老家,结果看到这样问题,菊花一紧.我擦,我刚加的 ...
- 谈一谈深度学习之semantic Segmentation
上一次发博客已经是9月份的事了....这段时间公司的事实在是多,有写博客的时间都拿去看paper了..正好春节回来写点东西,也正好对这段时间做一个总结. 首先当然还是好好说点这段时间的主要工作:语义分 ...
- 蓝的成长记——追逐DBA(5):不谈技术谈业务,恼人的应用系统
***************************************声明*************************************** 个人在oracle路上的成长记录,当中 ...
随机推荐
- mysql @value := 用法
背景 有这么一张表,记录名字和分数,现在需要按照成绩排名,存在并列名次的情况 解决方法 思路:按照score从大到小排序,第一行数据就是第一名,第二行就是第二名......需要判断当前行的score和 ...
- 【Centos】yum安装MySQL
安装步骤 1. 点击此处下载MySQL的YUM源 -- [ MySQL RPM] 选择适合你平台的rpm,我的是centos7 2. 安装MySQL的yum源,即RPM sudo yum locali ...
- vue-cli脚手架npm相关文件解读(1)webpack.base.conf.js
系列文章传送门: 1.build/webpack.base.conf.js 2.build/webpack.prod.conf.js 3.build/webpack.dev.conf.js 4.bui ...
- Android笔记: 播放提示音 的简单方法
public static void sendSound(Context mContext) { //上下文 Uri mUri= RingtoneManager.getDefaultUri(Ringt ...
- Servlet知识点
如果请求采用Get方式,则重写doGet()方法,如果请求采用Post方式,则重写doPost()方法. 下面是重写doGet()方法的servlet例子. servlet继承如下类: 整体结构: 在 ...
- [读书笔记] 二、条件注解@Conditional,组合注解,元注解
一.条件注解@Conditional,组合注解,元注解 1. @Conditional:满足特定条件创建一个Bean,SpringBoot就是利用这个特性进行自动配置的. 例子: 首先,两个Condi ...
- 一步步带你做vue后台管理框架(一)——介绍框架
系列教程<一步步带你做vue后台管理框架>第一课 github地址:vue-framework-wz 线上体验地址:立即体验 在如今的科技公司中有很多前端的需求都是要写一个类似于后台管理框 ...
- AOP入门之静态代理
代理模式 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问. 在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 代理模式一般涉及 ...
- (转载)理解Java中的引用传递和值传递
关于Java传参时是引用传递还是值传递,一直是一个讨论比较多的话题,有论坛说Java中只有值传递,也有些地方说引用传递和值传递都存在,比较容易让人迷惑.关于值传递和引用传递其实需要分情况看待,今天 ...
- 【DDD】领域驱动设计精要
本文算是<领域驱动设计>这本书的读书笔记,加上自己的一些读后感.网上有很多这本书的读书笔记,但是都是别人的,不如自己总结的理解深刻.建议大家在读这本书时结合<实现领域驱动设计> ...