一、理论层面

内置锁与互斥锁

修饰普通方法、修饰静态方法、修饰代码块

package com.roocon.thread.t3;

public class Sequence {
private static int value; // synchronized放在普通方法上,内置锁就是当前方法的实例
public synchronized int getNext(){
return value++;
} // synchronized修饰静态方法,内置锁就是当前的Class字节码对象Sequence.class
public static synchronized int getPrevious(){
return value--;
} public int xx(){
// synchronized修饰静态代码块,则锁的是任意一个对象
/*
synchronized (this){ }
synchronized (Integer.valueOf(value)) { }
synchronized (Sequence.class) { }
*/
synchronized (Sequence.class) {
if (value > 0) {
return value;
}else {
return -1;
}
}
}
public static void main(String[] args) {
Sequence sequence = new Sequence();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
System.out.println(Thread.currentThread().getName()+" "+sequence.getNext());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
System.out.println(Thread.currentThread().getName()+" "+sequence.getNext());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
System.out.println(Thread.currentThread().getName()+" "+sequence.getNext());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}

二、JVM层面

查看xx方法同步代码块字节码:

查看同步方法字节码:

任何对象都可以作为锁,那么锁信息又存在对象的什么地方呢?

存在对象头中。

对象头中的信息:

  Mark Word

  Class Metadata Address 类的类型地址

  Array Length

1.偏向锁:

每次获得锁和释放锁会浪费资源(消耗时间),很多情况下,竞争锁不是由多个线程,而是由一个线程在使用。线程在获取锁时,会依据对象头Mark word信息进行判断执行。

对象头Mark word中会保存如下信息:

  线程id

  Epoch

  对象的分代年龄信息

  是否是偏向锁

  锁标志位

偏向锁在获取锁之后,如果没有竞争,也就是一直是这个线程在获取锁,那么当这个线程第二次再来进入该方法时,不需要再去获取锁了,也不需要释放锁,这样,就节省了大量的获取锁释放锁的资源。那么,什么时候会释放锁呢?只有当存在竞争时,才会去释放锁。

偏向锁适用于什么场景?

只有一个线程在访问同步代码块的场景。

2.轻量级锁:可以同时让多个线程进入同步代码块。自旋锁就是轻量级锁。

轻量级锁是如何加锁的?

在线程执行同步代码块之前,jvm会先在当前线程的栈帧中创建用于存储锁记录的存储空间。

(栈帧是什么?虚拟机栈中存储的是一个一个的栈帧,栈帧中存储了方法的执行信息,每个方法都会伴随着栈帧的进栈和出栈)

然后呢,并将对象头中的mark word复制到锁记录中。然后呢,开始竞争锁就可以了。竞争成功之后,markword就改变了,会将锁标志位改成轻量级锁。接着,开始执行同步体。

另外一个线程也想获得该锁。同样,它也将对象头中的mark word复制到锁记录中,它发现已经被其他线程获得了锁,所以它修改不成功。于是,它就不停的去修改,不停的失败,直到第一个线程把这个锁释放了,它就可以修改成功了。刚才这一个过程,就是所谓的自旋锁。

3.重量级锁

什么是重量级锁?就是,这个线程获得锁进入之后,其他线程必须在外面等待。synchronized就是重量级锁。

三、总结

上面只是对synchronized 如何实现同步功能的一个视频学习总结,更加细节的深入原理可以参考下面两篇文章:

synchronized的实现原理

深入理解Java并发之synchronized实现原理

参考资料:

《java并发编程与实战》龙果学院

Java并发编程原理与实战九:synchronized的原理与使用的更多相关文章

  1. Java并发编程系列-(8) JMM和底层实现原理

    8. JMM和底层实现原理 8.1 线程间的通信与同步 线程之间的通信 线程的通信是指线程之间以何种机制来交换信息.在编程中,线程之间的通信机制有两种,共享内存和消息传递. 在共享内存的并发模型里,线 ...

  2. Java并发编程(七)ConcurrentLinkedQueue的实现原理和源码分析

    相关文章 Java并发编程(一)线程定义.状态和属性 Java并发编程(二)同步 Java并发编程(三)volatile域 Java并发编程(四)Java内存模型 Java并发编程(五)Concurr ...

  3. Java并发编程知识点总结Volatile、Synchronized、Lock实现原理

    Volatile关键字及其实现原理 在多线程并发编程中,Volatile可以理解为轻量级的Synchronized,用volatile关键字声明的变量,叫做共享变量,其保证了变量的“可见性”以及“有序 ...

  4. 【Java并发编程之深入理解】Synchronized的使用

    原文:https://blog.csdn.net/zjy15203167987/article/details/82531772 1.为什么要使用synchronized 在并发编程中存在线程安全问题 ...

  5. 转:【Java并发编程】之十九:并发新特性—Executor框架与线程池(含代码)

      Executor框架简介 在Java5之后,并发编程引入了一堆新的启动.调度和管理线程的API.Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.coc ...

  6. 转:【Java并发编程】之七:使用synchronized获取互斥锁的几点说明

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17199201     在并发编程中,多线程同时并发访问的资源叫做临界资源,当多个线程同时访 ...

  7. 【Java并发编程】之七:使用synchronized获取互斥锁的几点说明

    在并发编程中,多线程同时并发访问的资源叫做临界资源,当多个线程同时访问对象并要求操作相同资源时,分割了原子操作就有可能出现数据的不一致或数据不完整的情况,为避免这种情况的发生,我们会采取同步机制,以确 ...

  8. java并发编程学习: 阻塞队列 使用 及 实现原理

    队列(Queue)与栈(Stack)是数据结构中的二种常用结构,队列的特点是先进先出(First In First Out),而Stack是先进后出(First In Last Out),说得通俗点: ...

  9. java并发编程的艺术(四)---ConcurrentHashMap原理解析

    本文来源于翁舒航的博客,点击即可跳转原文观看!!!(被转载或者拷贝走的内容可能缺失图片.视频等原文的内容) 若网站将链接屏蔽,可直接拷贝原文链接到地址栏跳转观看,原文链接:https://www.cn ...

  10. Java 并发编程中使用 ReentrantLock 替代 synchronized 关键字原语

    Java 5 引入的 Concurrent 并发库软件包中,提供了 ReentrantLock 可重入同步锁,用来替代 synchronized 关键字原语,并可提供更好的性能,以及更强大的功能.使用 ...

随机推荐

  1. BZOJ 3132(上帝造题的七分钟-树状数组求和+2D逆求和数组)

    3132: 上帝造题的七分钟 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 46  Solved: 18[Submit][Status][Discus ...

  2. C语言中Union类型的使用方法

    转自:http://blog.csdn.net/feimor/article/details/6858103 使用C语言时,常常使用struct,对于union类型却几乎没有用过,只知道它是联合类型, ...

  3. Python入门:学会创建并调用函数

    这是关于Python的第4篇文章,主要介绍下如何创建并调用函数. print():是打印放入对象的函数 len():是返回对象长度的函数 input():是让用户输入对象的函数 ... 简单来说,函数 ...

  4. 经纬转换成point的sql

    .UPDATE xx.zd_kakou_info t,(SELECT kakou_id, kakou_lon,kakou_lat,CONCAT('POINT(' , kakou_lon ,' ',ka ...

  5. 【php】new static的用法

    在一个类中,常见的是new self()操作,代表返回自身类的实例. 当父类中存在方法,然后每个子类继承于父类,调用这个方法会返回自身的实例化对象, <?php class A { functi ...

  6. 小程序 获取用户的openid

    wx.login({ success: res => { var code = res.code; //返回code // 小程序appid var appId = 'wxd751fc845c9 ...

  7. Laravel 5.1 中的异常处理器和HTTP异常处理 abort()

    原文  http://laravelacademy.org/post/1867.html 错误和异常是处理程序开发中不可回避的议题,在本地开发中我们往往希望能捕获程序抛出的异常并将其显示打印出来,以便 ...

  8. es6 很简单

    es6出了许多好的,优秀的特性.下面列举一些常用的 其实这些特性都很好理解,一两句话就可以表达出来看.主要是对旧的写法的一种改进. function  加了一些语言糖,传参更方便 class      ...

  9. MySQL复制 -- 复制出错怎么办?

    假如我们生产环境复制出错?该怎么办呢? 下面提供几种办法: 1. 手工处理,补回不一致数据(可以利用主库来补数据.也可以利用binlog来补数据) 2.用开源工具来解决一致性问题 3.自己造轮子,解决 ...

  10. myeclipse8.6 注册码

    MyEclipse8.6 注册码 别处找的均是8.6版本,可以使用到2014年一:MyEclipse Standard Edition: zhucemLR7ZL-655954-695876566190 ...