系列文章目录
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、设计同步器的意义
- 共享资源可以同时被多个线程访问
- 资源可以在其生命周期内被修改
引出的问题:
由于线程执行的过程是不可控的,所以需要采用同步机制来协同对对象可变状态的访问!
1.如何解决线程并发安全问题?
java中有两种方式实现同步互斥访问:synchronized和Lock 同步器的本质是加锁 加锁的目的:同一个时刻只有一个线程被访问。
二、synchronized原理详解
加锁的方式:
- 同步实例方法,锁是当前实例对象
- 同步类方法,锁是当前类对象
- 同步代码块,锁是括号里面的对象
1.synchronized底层原理
synchronized基于JVM内置锁实现的,通过内部对象monitor实现,JVM内置锁在1.5之后做了很多优化,如:锁粗化,所消除、轻量级锁、偏向锁、适应性锁、适应性锁等技术来减少操作的开销。 synchronized关键字被编译成字节码后会被翻译成monitorenter 和 monitorexit 两条指令分别在同步块逻辑代码的起始位置与结束位置。 每个同步对象都有一个自己的Monitor(监视器锁),加锁过程如下:
2.什么是monitor?
可以把它理解为 一个同步工具,也可以描述为 一种同步机制,它通常被 描述为一个对象。 所有的对象都是天生的Monitor,java对象带有一把锁,内部锁或者Monitor锁。也就是Synchronized的对象锁,MarkWord锁标识位于10,其中指针指向的是Monitor对象的起始地址。Monitor是由ObjectMonitor实现的,C++实现。
1 ObjectMonitor() {
2 _header = NULL;
3 _count = 0;
4 _waiters = 0,
5 _recursions = 0;
6 _object = NULL;
7 _owner = NULL;
8 _WaitSet = NULL;
9 _WaitSetLock = 0 ;
10 _Responsible = NULL ;
11 _succ = NULL ;
12 _cxq = NULL ;
13 FreeNext = NULL ;
14 _EntryList = NULL ;
15 _SpinFreq = 0 ;
16 _SpinClock = 0 ;
17 OwnerIsThread = 0 ;
18 }
同时:notify/notifyAll/wait等方法会使用到Monitor锁对象,monitor对象存在于每个Java对象的对象头Mark Word中(存储的指针的指向),Synchronized锁便是通过这种方式获取锁的。这也是为什么每个对象都可以被锁住的原因。
三、对象的内存布局
1.对象头
比如 hash码,对象所属的年代,对象锁,锁状态标志,偏向锁(线程)ID,偏向时间,数组长度(数组对象)等。Java对象头一般占有2个机器码(在32位虚拟机中,1个机器码等于4字节,也就是32bit,在64位虚拟机中,1个机器码是8个字节,也就是64bit),但是 如果对象是数组类型,则需要3个机器码,因为JVM虚拟机可以通过Java对象的元数据信息确定Java对象的大小,但是无法从数组的元数据来确认数组的大小,所以用一块来记录数组长度。 HotSpot虚拟机的对象头包括两部分信息,第一部分是“Mark Word”,用于存储对象自身的运行时数据, 如哈希码 (HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等,它是实现轻量级锁和偏向锁的关键。
总结
提示:monitor简单总结
|