标签:静态 数据 实体 处理 png 存储 oracle inter monit
Java中的类大体可以分为2类,一种是隐式锁像Synchronized,是JVM级别的锁,一种是显示锁像Lock接口下的一些实现,是API级别的锁。
具体对象
:锁的是对象
;成员方法
:那锁的就是 this
;静态方法
:锁的就是这个对象.class
修饰方法(隐式同步)
我们写一个
public synchronized static void syntask()
这个方法的字节码文件
ACC_PUBLIC
代表public修饰ACC_STATIC
表示是静态方法ACC_SYNCHRONIZED
指明该方法为同步方法
所以当这个方法被调用时,jvm会检查ACC_SYNCHRONIZED是否被设置了,如果设置了,该线程就要求先成功持有管程(monitor),然后才能执行方法,最后等方法执行完成(正常完成或者非正常完成)才会释放管程
在方法执行期间,执行线程持有了管程,其他任何线程都无法再获取到同一个管程。
如果一个同步方法执行期间抛出了异常,并且在方法内部无法处理此异常,那这个同步方法所持有的管程将在异常抛到同步方法边界之外时自动释放
修饰代码块
public void syncTask(){ synchronized (this){ i++; } }
Java虚拟机的指令集中有 monitorenter 和 monitorexit 两条指令来支持 synchronized 关键字的语义。(monitorenter 和 monitorexit 两条指令是 C 语言的实现)正确实现 synchronized 关键字需要 Javac 编译器与 Java 虚拟机两者共同协作支持。Monitor的实现基本都是 C++ 代码,通过JNI(java native interface)的操作,直接和cpu的交互编程
我们知道在老版本的JDK中,这个锁的效率是很低下的,但是Oracle也对锁进行了一系列的优化。
偏向锁->自旋锁->轻量级锁->重量级锁。按照这个顺序,锁的重量依次增加。
研究发现,在大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,因此为了减少同一线程获取锁的代价而引入偏向锁。那么显然,一旦另一个线程尝试获得这个锁,那么偏向模式就会结束。另一方面,如果程序的大多数锁都是多个线程访问,那么偏向锁就是多余的。
轻量级锁是和传统的重量级锁相比较的,传统的锁使用的是操作系统的互斥量,而轻量级锁是虚拟机基于 CAS 操作进行更新,尝试比较并交换,根据情况决定要不要改为重量级锁。(这个动态过程也就是自旋锁的过程了)
重量级锁。重量级锁即为我们在上面探讨的具有完整Monitor功能的锁。
自旋锁。自旋锁是一个过渡锁,是从轻量级锁到重量级锁的过渡。也就是CAS。
在生成锁的时候,JVM会从最轻量级的锁开始创建,若不满足条件就会将锁升级
Lock是java JUC包下的显示锁,是一种API级别的锁,因此在效率层面依赖于程序员如何对锁进行使用,而synchronized是JVM级别的锁,JVM会自动进行优化。
Lock是一个接口,常用的实现类有:
ReentrantLock
)ReadLock
)WriteLock
)这些类的底层都是使用了AQS的同步机制,关于AQS请到我的另一篇文章
是java虚拟机提供的轻量级的同步机制:1.保证可见性,2不保证原子性,3禁止指令重排
Java内存模型:
由于jvm运行程序的实体是线程,而每个线程创建时Jvm都会为其创建一个工作内存,私有数据区域。java内存模型中规定所有变量存储在主内存,主内存时共享区域,所有线程都可以访问。 但线程对变量的操作必须在自己的工作内存执行,首先将变量从主内存拷贝到自己的工作内存空间,然后对变量进行操作,操作完成后再写入主内存
Compare and swap,是一条cpu并发原语,使用了大量的sun.misc.Unsafe类,原语的执行必须是连续的,在执行过程中不允许被打断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题
CAS缺点:
1.如果CAS失败,会一直进行尝试,如果CAS长时间一直不成功,可能会给cpu带来很大的开销。
2.只能保证一个共享变量的原子操作
3.ABA问题
什么是ABA问题?
两个线程由于存在时间差,线程一将A->B->A, 然后线程2查看的时候,以为数据没有进行变化,直接就进行了CAS,然而数据已经从A变成到B再变成A。
如果解决ABA问题?
使用带时间戳的原子引用
标签:静态 数据 实体 处理 png 存储 oracle inter monit
原文地址:https://www.cnblogs.com/williamGod/p/14885086.html