一、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. vue & watch props

    vue & watch props bug OK watch: { // props // chatObj: () => { // // bug // log(`this.chatObj ...

  2. GitHub & GitHub Package Registry

    GitHub & GitHub Package Registry npm https://github.blog/2019-05-10-introducing-github-package-r ...

  3. 精密进近OAS面的绘制与评估

    一.定义:精密进近OAS面(Obstacle Assessment Surface 障碍物评价面)是在精密进近程序中,用来对障碍物进行评估,找出影响运行标准的控制障碍物的一种计算方法. 二.构成 OA ...

  4. 教你吃透CSS的盒子模型(Box Model)

    CSS 盒子模型(Box Model) 所有HTML元素可以看作盒子,在CSS中,"box model"这一术语是用来设计和布局时使用. CSS盒模型本质上是一个盒子,封装周围的H ...

  5. LDAP启动TLS 完整操作流程

    配置LDAP启动TLS 阅读本文之前,建议初学的小伙伴先看一下上一篇:完整的 LDAP + phpLDAPadmin安装部署流程 (ubuntu18.04) 以下正文: 接下来的操作承接上文,还是在同 ...

  6. 细说MySQL连接查询:内连、左连和右连

    转: 细说MySQL连接查询:内连.左连和右连 简介: MySQL 的连接查询,通常都是将来自两个或多个表的行结合起来,基于这些表之间的共同字段,进行数据的拼接.首先,要确定一个主表作为结果集,然后将 ...

  7. springboot的4种属性注入

    1.Autowired注入 2.构造方法注入 3.@Bean方法形参注入 4.直接在@Bean方法上使用注解@ConfigurationProperties(prefix="jdbc&quo ...

  8. 如何在netcore下,愉快的使用IServiceProvider

    之前一直做dotnet framework开发,依赖注入使用Autofac,Autofac的一般用法是服务启动时,将用到的接口.实现类名注入进去, 然后在服务其他地方如果使用该类时,直接在Contai ...

  9. PAT-1086(Tree Traversals Again)Java语言实现+根据中序和前序遍历构建树并且给出后序遍历序列

    Tree Traversals Again Tree Traversals Again 这里的第一个tip就是注意到非递归中序遍历的过程中,进栈的顺序恰好是前序遍历的顺序,而出栈的顺序恰好是中序遍历的 ...

  10. CentOS7 安装 MySQL Cluster 7.6.7

    引用自:http://lemonlone.com/posts/mysql-ndb-cluster-install/ 仅做备份和配置文件更改 1.先在VMware中安装 CentOS-7-x86_64- ...