一、理论层面

内置锁与互斥锁

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

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. Beta冲刺 (7/7)

    队名:天机组 组员1友林 228(组长) 今日完成:封装代码 明天计划: 剩余任务:优化网络通讯机制 主要困难:暂无 收获及疑问:暂无 组员2方宜 225 今日完成:优化了一部分活动 明天计划:剩余活 ...

  2. 解决亚马逊云服务器上安装nginx后无法访问的问题

    在亚马逊云服务器上装了Ubuntu系统,使用docker环境搭建nginx,启动nginx容器后,在浏览器输入地址后,显示连接超时. 在网上查了一下说有可能是服务器安全组的设置问题 然后在云服务器的安 ...

  3. 配置高可用集群(实验) corosyne+pacemaker

    环境准备: 一准备三个虚拟机,把/etc/hosts/文件配置好                              192.168.43.9 node0                     ...

  4. docker删除为<none>的镜像

    $ docker stop $(docker ps -a | grep "Exited" | awk '{print $1 }')  //停止容器      $ docker rm ...

  5. Excel作为数据源TesTNG做数据驱动完整代码

    说明:EXCEL 支持xls 和xlsx 俩种格式 : 已经过测试 ! package main.java; import org.apache.poi.ss.usermodel.*; import ...

  6. angular 调用element的 onfocus onkeydown onblur等事件

    项目里要实现一个input验证通过就切换到下一个input的功能 当然用jq dom操作很简单  ,大家都懂,现在用 angular,mvc 数据模型控制分离,不想再dom操作怎么办 以下方法 < ...

  7. 在输入密码框中眼睛睁开可以看见数字,眼睛闭上看不见数字怎么用JS实现

    无论做那个项目,登录注册页面总是避免不了的,那怎么用js来控制密码的显示和隐藏呢?先看一下效果图: HTML代码如下: <div>         <label for=" ...

  8. Java并发编程实战3-可见性与volatile关键字

    1. 缓存一致性问题 在计算机中,每条指令都是在CPU执行的,而CPU又不具备存储数据的功能,因此数据都是存储在主存(即内存)和外存(硬盘)中.但是,主存中数据的存取速度高于外存中数据的存取速度(这也 ...

  9. ionic2如何升级到最新版本、配置开发环境

         好久没写东西了,去年用了angular2的RC版本和ionic2写了一个项目,因为开发周期和有些版本不稳定,所以一直没有升级,ng2新版本引用Aot打包,听说优化还不错,现在尝试升级ioni ...

  10. jsp中的下载链接

    1.下载链接jsp界面(a链接直接链文件可以看出文件在服务器中的路径,用servlet处理的链接则看不出) <%@ page language="java" contentT ...