java面试-synchronized底层实现机制
一、synchronized的三种应用方式
1、修饰实例方法,锁是当前实例对象,进入同步代码前要获得当前实例的锁
/**
* synchronized修饰实例方法,当前线程的锁是实例对象accountingSync
* 当一个线程正在访问一个对象的synchronized实例方法,那么其他线程不能访问该对象的其他synchronized方法
* 一个对象只有一把锁
*/
public class AccountingSync implements Runnable { static AccountingSync accountingSync = new AccountingSync();
//共享资源
static int i = 0;
static int j = 0; public synchronized void increase() {
i++;
} @Override
public void run() {
for(int i =0;i<1000000;i++){
synchronized (this){
increase();
}
}
} public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(accountingSync);
Thread thread2 = new Thread(accountingSync);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(i);
}
}
/**
* thread1访问实例对象obj1的synchronized方法,thread2访问实例对象obj1的synchronized方法
* 这样是允许的,因为两个实例对象锁并不相同。
* 此时如果两个线程操作数据非共享,线程安全有保证,如果数据共享,线程安全无法保证
*
*/
public class AccountingSyncBad implements Runnable { static int i = 0; public synchronized void increase() {
i++;
} @Override
public void run() {
for (int i = 0; i < 1000000; i++) {
increase();
}
} public static void main(String[] args) throws InterruptedException{
//new新实例
Thread thread1 = new Thread(new AccountingSyncBad());
//new新实例
Thread thread2 = new Thread(new AccountingSyncBad());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(i);
}
}
2、修饰静态方法,锁是当前类的 class对象,进入同步代码前要获得当前类对象的锁
public class AccountingSyncClass implements Runnable{
static int i = 0;
/**
* synchronized作用于静态方法,锁是当前class对象
*/
public static synchronized void increase() {
i++;
}
/**
* increase4Obj方法是实例方法,其对象锁是当前实例对象,
* 如果别的线程调用该方法,将不会产生互斥现象,毕竟锁对象不同,
* 但我们应该意识到这种情况下可能会发现线程安全问题(操作了共享静态变量i)。
*/
public synchronized void increase4Obj(){
i++;
}
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
increase();
// increase4Obj();
}
}
public static void main(String[] args) throws InterruptedException{
//new新实例
Thread thread1 = new Thread(new AccountingSyncClass());
//new新实例
Thread thread2 = new Thread(new AccountingSyncClass());
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(i);
}
}
3、修饰代码块
synchronized(this) 锁是当前实例对象,
synchronized(AccountingSync.class) 锁是class对象
二、synchronized代码块底层原理
synchronized代码块是由一对monitorenter和monitorexit指令实现的,Monitor对象是同步的基本实现单元。
三、java虚拟机对Synchronized的优化
1、当没有竞争出现时,默认会使用偏斜锁。JVM 会利用 CAS操作,在对象头上的Mark Word部分设置线程ID,以表示这个对象偏向于当前线程,所以并不涉及真正的互斥锁。这样做的假设是基于在很多应用场景中,大部分对象生命周期中最多会被一个线程锁定,使用偏斜锁可以降低无竞争开销。
2、有竞争出现时,当有另外的线程试图锁定某个已经被偏斜锁锁定的对象,jvm就会撤销revoke偏斜锁,并切换到轻量级锁。轻量级锁依赖CAS操作Mark Word来试图获取锁,如果成功,就使用轻量级锁,否则继续升级未重量级锁
PS:锁降级也是存在的,当JVM进入SafePoint安全点的时候,会检查是否有闲置的Monitor,然后试图进行降级。
java面试-synchronized底层实现机制的更多相关文章
- JAVA面试常见问题之锁机制篇
1.说说线程安全问题,什么是线程安全,如何保证线程安全 线程安全:就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用.不 ...
- java多线程synchronized底层实现
一直想把这个特别重要的关键词的底层实现搞明白.(当然现在也没有完全明白,如果有错误以后修改这篇文章) 首先,这个关键词synchronize可以说是个语法糖,它的具体用法网上很多博客都讲的比较明了了. ...
- java面试-synchronized与lock有什么区别?
1.原始构成: synchronized是关键字,属于JVM层面,底层是由一对monitorenter和monitorexit指令实现的. ReentrantLock是一个具体类,是API层面的锁. ...
- java面试-CAS底层原理
一.CAS是什么? 比较并交换,它是一条CPU并发原语. CAS是一种无锁算法,CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B.当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什 ...
- Java面试底层原理
面试发现经常有些重复的面试问题,自己也应该学会记录下来,最好自己能做成笔记,在下一次面的时候说得有条不紊,深入具体,面试官想必也很开心.以下是我个人总结,请参考: HashSet底层原理:(问了大几率 ...
- 面试突击39:synchronized底层是如何实现的?
想了解 synchronized 是如何运行的?就要先搞清楚 synchronized 是如何实现? synchronized 同步锁是通过 JVM 内置的 Monitor 监视器实现的,而监视器又是 ...
- java 多线程 synchronized与lock的通信机制等问题,结合相应实例说明
1. 利用多线程实现如下需求: 写两个线程,一个线程打印1~52,另一个线程打印A~Z,打印顺序是12A34B...5152Z: 2. 使用synchronized 实现 public class T ...
- java多线程02-----------------synchronized底层实现及JVM对synchronized的优化
java多线程02-----------------synchronized底层实现及JVM对synchronized的优化 提到java多线程,我们首先想到的就是synchronized关键字,它在 ...
- 死磕Synchronized底层实现,面试你还怕什么?
关于synchronized的底层实现,网上有很多文章了.但是很多文章要么作者根本没看代码,仅仅是根据网上其他文章总结.照搬而成,难免有些错误:要么很多点都是一笔带过,对于为什么这样实现没有一个说法, ...
随机推荐
- The State of JavaScript 2019
The State of JavaScript 2019 https://stateofjs.com/ https://survey.stateofjs.com/ https://2018.state ...
- windows10 安装NASM
NASM官网 下载NASM NASM在线HTML文档 下载golink golink文档 NASM教程 in windows x64调用约定 x86调用约定 编码样式约定 在编写nasm时数字默认为1 ...
- Redis 日志篇:系统高可用的杀手锏
特立独行是对的,融入圈子也是对的,重点是要想清楚自己向往怎样的生活,为此愿意付出怎样的代价. 我们通常将 Redis 作为缓存使用,提高读取响应性能,一旦 Redis 宕机,内存中的数据全部丢失,假如 ...
- ffmpeg第4篇:为视频添加动态水印
动态分为三种: 水印本身变化 水印显示时间变化 水印位置变化 水印本身变化 看过上一篇的小伙伴可能觉得第一种很简单,把jpg格式的图片换成gif格式的不就可以了吗,然而亲自试一下就会发现,把gif图片 ...
- mui调用本地相册调用相机上传照片
调用mui的常用库和jquery html部分: <header class="mui-bar mui-bar-nav"> <a class="mui- ...
- 读懂RESTful风格
RESTful就是资源定位和资源操作的风格.不是标准也不是协议. REST即Representational State Transfer的缩写,可译为"表现层状态转化".REST ...
- go的循环
目录 go的循环 一.语法 二.语法简写 1.省略第一部分 2.省略第二部分 3.省略第三部分 4.全省略:死循环 5.终极写法,简洁变形 go的循环 Go中只有for循环,没有while循环.因为w ...
- 215. 数组中的第K个最大元素 + 快速排序 + 大根堆
215. 数组中的第K个最大元素 LeetCode-215 另一道类似的第k大元素问题:https://www.cnblogs.com/GarrettWale/p/14386862.html 题目详情 ...
- 清华大学-成绩排序(排序+解决MLE问题)
成绩排序 成绩排序 这里需要注意的就是超内存的问题. 解决方法就是通过指针的方式,每次动态开n大小的内存,而不是一开始就分配. #include<bits/stdc++.h> using ...
- C语言经典88案例,我文科妹妹说她都学会了!
案例ex01: 将字符串转换为一个整数 1 题目 函数:fun() 功能:将字符串转换为一个整数 描述: [不能使用C语言提供的字符串函数] 输入:字符串"-1234" 输出:整型 ...