美文网首页
24 synchronized 线程锁原理:

24 synchronized 线程锁原理:

作者: 滔滔逐浪 | 来源:发表于2020-07-20 08:18 被阅读0次

遇到线程安全的时候需要使用synchronized

Synchronized关联到一个对象:
1,如果在普通方法上加上synchronized 当前this 锁;
2, 如果在静态方法上加上synchronized 当前class字节码
3,或者自定义锁对象
synchronized是一个java的关键字:
java 代码转c代码 转汇编代码;
synchronized 重入锁

package com.taotao.metithread;

/**
 *@author tom
 *Date  2020/7/20 0020 7:36
 *synchronized 重入锁
 */
public class Test005  extends  Thread{
    private Object lookobject=new Object();

    @Override
    public void run() {
        a();
    }

    private  void a() {
        synchronized (lookobject){
            System.out.println("我是a调用b");
            b();
        }
    }

    private void b() {
        synchronized (lookobject){
            System.out.println("我是b");
        }
    }

    public static void main(String[] args) {
        new Test005().start();
    }
}



java 代码如何变成汇编代码 javap -p -v class 文件
java编译class文件,
Monitorenter/Monitorexit

monitorenter

  1. monitorenter官方解释:

<u>https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.monitorenter</u>

翻译过来:

每一个对象都会和一个监视器monitor关联。监视器被占用时会被锁住,其他线程无法来获

取该monitor。 当JVM执行某个线程的某个方法内部的monitorenter时,它会尝试去获取当前对象对应的monitor的所有权。其过程如下:

1. 若monior的进入数为0,线程可以进入monitor,并将monitor的进入数置为1。当前线程成为monitor的owner(所有者)

2. 若线程已拥有monitor的所有权,允许它重入monitor,则进入monitor的进入数加1

3. 若其他线程已经占有monitor的所有权,那么当前尝试获取monitor的所有权的线程会被阻塞,直

到monitor的进入数变为0,才能重新尝试获取monitor的所有权。

monitorenter小结:

synchronized的锁对象会关联一个monitor,这个monitor不是我们主动创建的,是JVM的线程执行到这个同步代码块,发现锁对象没有monitor就会创建monitor,monitor内部有两个重要的成员变量owner:拥有这把锁的线程,recursions会记录线程拥有锁的次数,当一个线程拥有monitor后其他线程只能等待

Monit才是真正的锁,是一个c++对象

Owner 拥有锁的线程

Recursions 记录获取锁的次数

monitorexit

<u>https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.monitorexit</u>

翻译过来:

1. 能执行monitorexit指令的线程一定是拥有当前对象的monitor的所有权的线程。

2. 执行monitorexit时会将monitor的进入数减1。当monitor的进入数减为0时,当前线程退出monitor,不再拥有monitor的所有权,此时其他被这个monitor阻塞的线程可以尝试去获取这个

monitor的所有权

monitorexit释放锁。

monitorexit插入在方法结束处和异常处,JVM保证每个monitorenter必须有对应的monitorexit。

为什么会有两个monitorexit,因为 Synchronized锁的同步代码块如果抛出异常的情况下,则自动释放锁。

通过monitorexit 去监听锁;1.判断_owner 是否为空,空则获取锁,其他线程进行阻塞, _recursions 归数加一,在进入另外个锁的时候在进行判断 _owner如果_owener相同,递归数_recursions加1,
当退出锁时 递归数减1;

一个同步代码块里有2个退出(monitorexit),一个是正常退出,一个是异常退出;

在Java虚拟机(HotSpot)中,monitor是有ObjectMonitor实现的(C++实现的,位于HotSpot虚拟机源码\openjdk8\openjdk\hotspot\src\share\vm\runtime\ObjectMonitor.hpp文件),其主要数据结构如下


ObjectMonitor() {
    _header       = NULL;
    _count        = 0;  // 记录个数
    _waiters      = 0,
    _recursions   = 0;   // 递归次数/重入次数
    _object       = NULL;
    _owner        = NULL; // 记录当前持有锁的线程ID
    _WaitSet      = NULL;  // 等待池:处于wait状态的线程,会被加入到_WaitSet
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ;
    FreeNext      = NULL ;
    _EntryList    = NULL ;  // 锁池:处于等待锁block状态的线程,会被加入到该列表
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
    _previous_owner_tid = 0;
  }

站在虚拟机源码分析

<u>http://hg.openjdk.java.net/jdk8</u> 下载hotspot虚拟机

_Owner 记录当前监视器被哪个线程持有, 要么是空或者当前自己,
_exq 竞争:排列正在获取锁的线程(当前我们的锁没有被任何线程持有)
_EntryList锁池:当前的锁已经被其他的线程持有,存放都是没有获取锁正在阻塞的线程。
_waitSet: 等待池 通过锁wait 方法,当前的线程会变为阻塞状态放入到_waitet
在调用notify 方法的 唤醒 等待 池中的正在等待的线程,到锁池中等待池-锁池

当T1被唤醒后需要重新竞争

java 对象布局: 对象头(Mark word /class 指针),实例数据,填充数据

package com.taotao.metithread;
import  org.openjdk.jol.info.ClassLayout;
/**
 *@author tom
 *Date  2020/7/20 0020 9:21
 *查看类型占的字节情况
 */
public class MeiteLock {
    private  int userId;

    public static void main(String[] args) {
        MeiteLock meiteLock=new MeiteLock();
        System.out.println(ClassLayout.parseInstance(meiteLock).toPrintable());
    }
}


image.png

分析: 对象头 16个字节 实例属性4个-20个字节/8+填充4个 24/8

new对象请问占用多少字节? 对象头(16) ,没有压缩的情况下+实例属性(填充)

基本数据类型占多少字节

1、bit --位:位是计算机中存储数据的最小单位,指二进制数中的一个位数,其值为“0”或“1”。
2、byte --字节:字节是计算机存储容量的基本单位,一个字节由8位二进制数组成。在计算机内部,一个字节可以表示一个数据,也可以表示一个英文字母,两个字节可以表示一个汉字。
64位/8
1Byte=8bit  (1B=8bit) 
1KB=1024Byte(字节)=8*1024bit
1MB=1024KB
1GB=1024MB

1TB=1024GB

int     32bit  4  
short   16bit  2
long     64bit 8
byte     8bit
char     16bit
float   32bit
double   64bit
boolean 1bit

相关文章

网友评论

      本文标题:24 synchronized 线程锁原理:

      本文链接:https://www.haomeiwen.com/subject/nljqkktx.html