一、Synchronized的概念

是利用锁的机制来实现同步的。

锁机制有如下两种特性:

互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操作)进行访问。互斥性我们也往往称为操作的原子性。

可见性:必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作从而引起不一致。

二、Synchronized的使用

修饰静态方法

  

//修饰静态方法
public static synchronized void print() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"runing");
}

  

修饰非静态方法

  

//修饰非静态方法
public synchronized void print1() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"runing");
}

  

修饰代码块

//代码块的使用
public void prnit2() {
synchronized (this) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"runing");
} } //代码块的使用
public void prnit3() {
synchronized (SynchroTest.class) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"runing");
} }

  

疑问:修饰代码块的时候,Synchronized参数对象起到了什么作用?

答:当JVM是用ClassLoader加载字节码的时候,会在方法区创建一个对象,同时也会在堆去创建一个Class(注意是大写的)。使用Synchronized.xxx.class就是说明所有Class对应的对象都使用共同一个锁(比较抽象)。详情请看原理分析JVM指令分析的 Monitorenter,Monitorexit。JVM会将对象与Monitor相关联。

java中每一个对象都会有一个monitor对象(监视器)。它的作用就是给对象加锁用的。

  1. 某一线程占有这个对象的时候,先看monitor的计数器是不是为0,如果是0说明还没有线程占有,此时会将monitor的计数器+1.如果不为0,表示有其他线程占有这个对象,需要等待。当占有这个对象的线程释放这个对象的时候,那么此时会将这个对象的monitor-1(并不是monitor=0,而是-1)。类似于CPU中的cache line作用。

三、Synchronized的原理分析

线程堆栈分析(互斥性)

public static void main(String[] args) throws InterruptedException {
final SynchroTest tSynchroTest1 = new SynchroTest();
for (int i = 10; i < 15; i++) {
new Thread(tSynchroTest1::print1).start();
}
} // 修饰非静态方法
public synchronized void print1() {
try {
TimeUnit.MINUTES.sleep(2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "runing");
}

  

根据以上代码进行分析。

    • jconsole分析,可以看出当前拥有对象锁的Thread-3因为线程睡眠,所以状态为TIMED_WAITING(等待状态)。看Thread-2可以看出总阻止数为1,也就是BLOCKED状态(上锁状态)。

    • jstack pid分析也可以看到dos命令窗口中的当前用对象线程是TIME_WAITING,阻塞线程是BLOCKED

  • JVM的指令分析
  1. javap(反编译)使用cmd,找到calss文件路径  D:\workspace1\GuaHao\bin\BlockQueueTest>javap -v SynchroTest。代码块的一个加锁方式,是使用Monitorenter、Monitorexit配合使用

    • 细心的朋友上图会看到51有一个monitorexit  和 56还有一个monitorexit?为什么会有两个互斥出口
    • 答:51行是正常出口,56是一个异常出口。当程序发生运行时异常的时候会从56monitorexit跳出。

    2.方法加锁方式,是使用、配合使用

  对象与monitor:一个实例对象包含了对象头,实例变量,填充数据。

  对象头:加锁的一个基础。

  实例变量:私有变量,属性变量信息

  填充数据:对象的启示地址,8字节表示。

对象头

  

  • JDK6之前 Synchronized是重量锁,比较暴力。
  • JDK6之后 添加了

    1. 偏向锁:再对象第一次被某一线程占有的时候,是否偏向锁置1,锁表01,写入线程号;当其他的线程访问的时候,就会竞争,结果分别是失败和成功。很多次被第一线程占有它的线程获得次数比较多此时就是偏向锁。相当于找对象(女朋友),当这个对象与第一个男人分手后,找到第二个男人之后,可能还会去找前男友,这就是属于偏向锁。竞争不激烈的时候使用。偏向锁与无所状态时间很接近。CAS算法campare and set(留个小作业,什么叫CAS算法?)
    2. 轻量级锁:线程有交替适用,互斥性不是很强,使用CAS算法不在适用,锁标志00。
    3. 重量级锁:强互斥,锁标记10,等待时间长。

      他们的区别是时间上的区别。

      用户线程和核心线程相互转换(非常耗时)

      由偏向锁转轻量级锁在转重量级锁的时候存在不可逆行为,只能低转高,不可反之。

      自旋锁:再转换过程中还存在一个叫做自旋锁的情况,再轻量级装重量级的时候,并不是马上从用户线程转成核心线程,再互斥的情况下会执行几 次空循环,如果空循环完成后再没有拿到占有权,则才会进行转换。

      消除锁:JIT(编译)的时候如果定义一个int i=0,并对这个定义进行加锁,那么由于上篇文章说道了,定义int i=0,是存在原子性的,所以这个这 个锁会在编译期间自动消除,防止JVM产生不必要的资源浪费

      CAS算法:引用GA特大的Java VAS原理深度分析文章  https://blog.csdn.net/tanga842428/article/details/52742698

      

欢迎大家来提问,如果有不理解的可以再评论区提出,我会定时解惑。

同舟共济,新海同航

什么是偏向锁:如何证明?
跟着路神一起开车证明呀,哈哈。我们的Synchronized关键字会调用OS(操作系统)中的pthread_mutex_lock()方法,然后修改此方法,再此方法中打印一句话,如果每次都输出说明次Synchronized非偏向锁。如果只打印一次,说明我们的synchronized本次是偏向锁,如此就证明了JVM中的偏向锁的存在。Synchronized关键字会再第一次调pthread_mutex_lock(),如果是偏向锁,则不在调用,非偏向锁则会多次调用

     

并发2-Synchronized的更多相关文章

  1. 5.并发编程-synchronized 细节说明

    并发编程-synchronized 细节说明 1. synchronized-锁重入 & 异常释放锁 说明 * 关键字synchronized 拥有锁重入的功能,也就是在使用synchroni ...

  2. Java并发分析—synchronized

    在计算机操作系统中,并发在宏观上是指在同一时间段内,同时有多道程序在运行. 一个程序可以对应一个进程或多个进程,进程有独立的存储空间.一个进程包含一个或多个线程.线程堆空间是共享的,栈空间是私有的.同 ...

  3. Java并发编程-synchronized

    多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同步用以解决多个线程同时访问时可能出现的问题.同步机制可以使用synchronized关键字实现.synchronized关 ...

  4. 悲观的并发策略——Synchronized互斥锁

    volatile既然不足以保证数据同步,那么就必须要引入锁来确保.互斥锁是最常见的同步手段,在并发过程中,当多条线程对同一个共享数据竞争时,它保证共享数据同一时刻只能被一条线程使用,其他线程只有等到锁 ...

  5. Java并发编程-synchronized指南

    在多线程程序中,同步修饰符用来控制对临界区代码的访问.其中一种方式是用synchronized关键字来保证代码的线程安全性.在Java中,synchronized修饰的代码块或方法不会被多个线程并发访 ...

  6. Java并发—–深入分析synchronized的实现原理

    记得刚刚开始学习Java的时候,一遇到多线程情况就是synchronized,相对于当时的我们来说synchronized是这么的神奇而又强大,那个时候我们赋予它一个名字“同步”,也成为了我们解决多线 ...

  7. 对象和变量的并发访问synchronized解析以及死锁分析排查

    一.synchronized java并发编程中存在“非线程安全"问题.“非线程安全"是指发生在多个线程对同一个对象中的实例变量并发访问时,产生的”脏读“现象,使用synchron ...

  8. 多线程与高并发(三)synchronized关键字

    上一篇中学习了线程安全相关的知识,知道了线程安全问题主要来自JMM的设计,集中在主内存和线程的工作内存而导致的内存可见性问题,及重排序导致的问题.上一篇也提到共享数据会出现可见性和竞争现象,如果多线程 ...

  9. Java并发,synchronized锁住的内容

    synchronized用在方法上锁住的是什么? 锁住的是当前对象的当前方法,会使得其他线程访问该对象的synchronized方法或者代码块阻塞,但并不会阻塞非synchronized方法. 脏读 ...

  10. java并发编程--Synchronized的理解

    synchronized实现锁的基础:Java中每一个对象都可以作为锁,具体表现为3种形式. (1)普通同步方法,锁是当前实例对象 (2)静态同步方法,锁是当前类的Class对象 (3)同步方法块,锁 ...

随机推荐

  1. 使用css borer实现图层蒙版效果

    需要js 思路:假设目标元素是target.在外层定义元素宽高等于target,通过border设置元素铺满整个文档,设置border的透明图,实现蒙版,在元素的内部设置子元素,宽高100%;设置圆角 ...

  2. Pascal学生管理

    program Project2; {$APPTYPE CONSOLE} uses SysUtils; ;M=; type date=record day:..; month:..; year:..; ...

  3. hdu4608 I-number

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4608 题意:给定一个数X,注意X是个大数,X的长度不超过1e5. 让你求出一个Y,满足三个条件,Y&g ...

  4. bzoj 1407: [Noi2002]Savage【扩展欧几里得+中国剩余定理】

    首先答案不会很大,所以枚举答案m,于是把问题转为了判定: 关于如何判定: 首先题目中虽然没说但是数据是按照初始洞穴编号排的序,所以并不用自己重新再排 假设当前答案为m,相遇时间为x,野人i和j,那么可 ...

  5. 【插件开发】—— 5 SWT控件以及布局使用

    前文回顾: 1 插件学习篇 2 简单的建立插件工程以及模型文件分析 3 利用扩展点,开发透视图 4 SWT编程须知 经过前几篇的介绍,多少对SWT又有了一些认识,那么这篇继续来看一下一些控件的组合使用 ...

  6. ionic2 angular2 模板指令补充

    向div中插入带有html标签的数据   [innerHTML]="item.content"    字符串截取指令                       {{item.de ...

  7. Linux 入门学习教材

    我大约从两年前开始接触Linux,在那之前工作中用的都是MCU,arm-cortex M系列的. 从单片机转向Linux学习,经历了很多的困难,刚开始都不知道怎么去编译, 网上也没有找到基础的教程,后 ...

  8. 面试基础试题 一 http和HTTPS的区别

    作为老生常谈的问题,我主要给出我自己的理解和结合大牛的叙述的综合看法,来检验自己学习 超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何 ...

  9. ————————C语言中快速排序方法——————————————

    在对浮点型排序是一定要用三木运算符(三目运算符内容下去自己看),因为如果也是用整形那样的减法的时候如果是两个十分相近的数字 可能返回一个小数(自己一会去试试),冉冉他cmp返回值是int(试试别的)因 ...

  10. Jmeter常见问题汇总(不断更新ing)

    1.测试计划中有多个线程组执行时,为了防止线程组间的相互干扰,需要如下设置一下:     2,接口测试中的上传字段为汉字时需要进行什么形式的转码? 方法一:需要把编码复选框勾选,才能正常通过接口查询数 ...