多线程共享内存,须要解决两个问题:多线程
竞态条件 内存可见性
可使用Synchronized 解决上面的问题
从几个方面来理解synchronized测试
可重入性 内存可见性 死锁 可重入性是synchronized 一个特色,原理以下: 可重入锁是记录锁的持有线程,和持有数量来实现的,当被synchronized 保护的代码时 ,检查对象是否已经被锁,若是是,那么检查是否被当前的线程锁定。若是是,增长持有数量,若是不是被当前线程锁定,才加入等待队列,当释放锁时,减小持有数量,当数量变为0时才释放这个锁。 内存可见性 synchronized 处理保证原子操做外,还能够保证内存可见性。在释放锁的时候,内存会写回内存,得到锁,都会从内存中读取最新的数据。相对volatile 来讲, synchronized保持可见性的成本比较高。 提个问题,volitale 内存可见性是怎么实现的?什么是指令重排? 死锁 举个例子,A,B两个线程,A持有锁a,等待线程B,B持有锁b,等待线程B,这样就陷入了相互等待? 提个问题, 死锁的条件是啥? 如何避免死锁?
简单的来说,执行Synchronized方法过程大体以下:
尝试得到锁,若是能获得锁,那么继续,若是不能获得锁,那么进入等待队列.net
执行synchronized 修饰方法实体 释放锁,等待队列中有等待的线程,取出一个而且唤醒 synchronized能够来干什么? 修饰代码块 修饰一个方法 修饰一个静态的方法 修饰一个类 synchronized不须要主动释放锁 JVM 基于进入和退出Monitor对象来实现方法同步和代码块同步,monitorenter指令是在同步代码块开始位置,monitorexit是插入到方法结束处和异常处 Synchronized的实现原理 Synchronized是JVM实现的一种锁,其中锁的获取和释放分别是monitorenter和monitorexit指令。 该锁在实现上分为了偏向锁、轻量级锁和重量级锁,其中偏向锁在1.6是默认开启的,轻量级锁在多线程竞争的状况下会膨胀成重量级锁 偏向锁 当一线程访问同步块的时候,会在对象头和栈帧中的锁记录存储偏向锁的线程ID,之后该线程进入或者退出同步块时,不须要进行CAS操做来加锁或者解锁,只须要简单测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。若是测试成功,表示该线程得到了锁。若是测试失败,须要再测试一下Mark Word中偏向锁的标识是否设置为1(表示当前是偏向锁) ,若是没有设置,则使用CAS竞争锁,若是设置了,则尝试使用CAS将对象头的偏向锁指向当前线程。
轻量级锁线程
加锁 线程在执行同步块以前,JVM会先在当前线程的栈帧中建立用于存储锁的记录空间,并将对象头中的MarkWord字段复制到锁记录中,固然会线程尝试使用CAS将对象头中的Mark Word替换成指向锁记录的指针。若是得到成功,当前线程得到了锁,若是失败,表示其余线程竞争锁,当前线程采用CAS来获取锁。 解锁 轻量级锁解锁的时候,会使用原子的CAS操做将 锁记录中的Mark Word 替换会对象头,若是成功,表示没有竞争发送,若是失败,当前存在锁竞争,锁就会膨胀成重量级锁。一旦锁变成了重量级锁,就不会再恢复到轻量级锁,当锁处于这个状态下,其余线程试图获取锁是,都会被阻塞,当持有的线程释放锁以后会唤醒这些线程,被唤醒的线程开始新一轮的锁争抢。
版权声明:本文为CSDN博主「wangxiaoming」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处连接及本声明。
原文连接:https://blog.csdn.net/wangmin...指针