一、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虚拟机对sychronized进行了优化,引入了偏斜锁、轻量级锁、重量级锁

三、java虚拟机对Synchronized的优化

JVM优化synchronized运行的机制,当JVM检测到不同的竞争情况时,会自动切换到适合的锁实现

1、当没有竞争出现时,默认会使用偏斜锁。JVM 会利用 CAS操作,在对象头上的Mark Word部分设置线程ID,以表示这个对象偏向于当前线程,所以并不涉及真正的互斥锁。这样做的假设是基于在很多应用场景中,大部分对象生命周期中最多会被一个线程锁定,使用偏斜锁可以降低无竞争开销。

2、有竞争出现时,当有另外的线程试图锁定某个已经被偏斜锁锁定的对象,jvm就会撤销revoke偏斜锁,并切换到轻量级锁。轻量级锁依赖CAS操作Mark Word来试图获取锁,如果成功,就使用轻量级锁,否则继续升级未重量级锁

PS:锁降级也是存在的,当JVM进入SafePoint安全点的时候,会检查是否有闲置的Monitor,然后试图进行降级。

java面试-synchronized底层实现机制的更多相关文章

  1. JAVA面试常见问题之锁机制篇

    1.说说线程安全问题,什么是线程安全,如何保证线程安全 线程安全:就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用.不 ...

  2. java多线程synchronized底层实现

    一直想把这个特别重要的关键词的底层实现搞明白.(当然现在也没有完全明白,如果有错误以后修改这篇文章) 首先,这个关键词synchronize可以说是个语法糖,它的具体用法网上很多博客都讲的比较明了了. ...

  3. java面试-synchronized与lock有什么区别?

    1.原始构成: synchronized是关键字,属于JVM层面,底层是由一对monitorenter和monitorexit指令实现的. ReentrantLock是一个具体类,是API层面的锁. ...

  4. java面试-CAS底层原理

    一.CAS是什么? 比较并交换,它是一条CPU并发原语. CAS是一种无锁算法,CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B.当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什 ...

  5. Java面试底层原理

    面试发现经常有些重复的面试问题,自己也应该学会记录下来,最好自己能做成笔记,在下一次面的时候说得有条不紊,深入具体,面试官想必也很开心.以下是我个人总结,请参考: HashSet底层原理:(问了大几率 ...

  6. 面试突击39:synchronized底层是如何实现的?

    想了解 synchronized 是如何运行的?就要先搞清楚 synchronized 是如何实现? synchronized 同步锁是通过 JVM 内置的 Monitor 监视器实现的,而监视器又是 ...

  7. java 多线程 synchronized与lock的通信机制等问题,结合相应实例说明

    1. 利用多线程实现如下需求: 写两个线程,一个线程打印1~52,另一个线程打印A~Z,打印顺序是12A34B...5152Z: 2. 使用synchronized 实现 public class T ...

  8. java多线程02-----------------synchronized底层实现及JVM对synchronized的优化

    java多线程02-----------------synchronized底层实现及JVM对synchronized的优化 提到java多线程,我们首先想到的就是synchronized关键字,它在 ...

  9. 死磕Synchronized底层实现,面试你还怕什么?

    关于synchronized的底层实现,网上有很多文章了.但是很多文章要么作者根本没看代码,仅仅是根据网上其他文章总结.照搬而成,难免有些错误:要么很多点都是一笔带过,对于为什么这样实现没有一个说法, ...

随机推荐

  1. [转]关于特征点法、直接法、光流法slam的对比

    转载网址:https://blog.csdn.net/weixin_38203573/article/details/79787499 特征点法: 通过特征点匹配来跟踪点,计算几何关系得到R,t,BA ...

  2. 玩遍博客网站,我整理了 Hugo 及其流行的风格主题

    搭建博客网站是个人进入互联网世界的最常见方式之一.伴随着网站技术的发展,如何搭建博客网站已经变得非常容易了.当然,你可以选择诸如 新浪博客.CSDN.博客园 之类的大型网站,快速创建依赖于大平台的个人 ...

  3. 微信小程序(二十)-UI组件(Vant Weapp)-01按装配置

    1.官网 https://vant-contrib.gitee.io/vant-weapp/#/intro https://gitee.com/vant-contrib/vant-weapp 2.按装 ...

  4. 前端传数据到后台,后台用实体类接收不到引发的思考----Java bean中字段命名潜规则

    1.按照Java语法规范,通常在实体类中的属性,首字母都是小写的.这是由于JavaBean的规范导致的.一般JavaBean属性都是首字母小写,以驼峰命名格式命名,相应的 getter/setter ...

  5. Ctfweb(2)

    CTFwebshow(2): phps源码泄露 思路:第一次接触phps这个后缀,第一眼打开的时候是想着用御剑去扫目录,但是很遗憾没有扫到index.phps,然后用burp抓包返回包信息也没有看到端 ...

  6. docker里运行docker命令

    一.概述 现有环境的jenkins是在docker里面运行的,需要执行docker相关命令才行. 关于基于docker搭建jenkins,请参考链接: https://www.cnblogs.com/ ...

  7. 剑指 Offer 62. 圆圈中最后剩下的数字 + 约瑟夫环问题

    剑指 Offer 62. 圆圈中最后剩下的数字 Offer_62 题目描述 方法一:使用链表模拟 这种方法是暴力方法,时间复杂度为O(nm),在本题中数据量过大会超时. 方法二:递归方法 packag ...

  8. 剑指 Offer 25. 合并两个排序的链表

    剑指 Offer 25. 合并两个排序的链表 Offer 25 该问题的原型就是多项式的合并. 实现较简单,没有特殊需要注意的问题. package com.walegarrett.offer; /* ...

  9. rest framework ViewSet

    ViewSets 路由选择确定要用于一个请求哪个控制器之后,控制器负责做出请求的感并产生相应的输出. - Ruby on Rails的文档 Django的REST框架允许你的逻辑一组在一个类中的相关意 ...

  10. Flutter Web 支持现已进入稳定版

    作者 / Mariam Hasnany, Product Manager, Flutter 我们对 Flutter 的愿景是成为一个可移植的 UI 框架,在全平台上构建精美的应用体验.做为 Flutt ...