Synchrnized

synchronized 关键字

synchronized的作用实现线程安全

首先说线程安全,实现线程安全有两种方式:一种是互斥同步,一种是非互斥同步

在java中实现互斥同步的最基本的方式就是使用synchronized关键字,这个关键字在编译以后会在同步的区域前后形成moniterenter和moniterexit两个字节码指令。这两个指令都需要一个引用来指定要锁定和解锁的对象,如果显示的指定了,那么就以指定对象作为refrece,如果没有指定,那么就看锁定的代码块是属于实例方法还是类方法,如果是实例方法,那么就锁定当前对象,如果是类对象,那么就锁定Class对象。

因为java中的线程与操作系统的线程是一对一的映射关系,所以java中的线程阻塞和唤醒都需要从用户态转化为内核态,消耗很多的处理器时间,所以称这个操作是重量级的,尤其是当代码块中的内容执行时间比切换内核态所需时间要快的多的时候,就造成了严重的浪费。因此引出了JUC,实现了非块的互斥同步,又在JDK版本以后实现了锁优化

锁优化:

synchronized有了锁升级的过程,关于这个升级过程有牵扯到了对象头信息,对象头中markWord中有

如果是没有锁的话,那么markword中存放的是对象的hash码,分代年龄

如果是偏向锁,那么markword中存放的就是偏向锁的id,偏向时间戳,分代年龄

如果是轻量级锁,那么就存放的指向锁记录的指针

如果是重量级锁,那么就存放的是指向重量级锁的指针

无锁情况与普通情况无区别, 这里不做介绍,如果是偏向锁,就是一段时间内只有一个线程频繁的进出代码块,那么就将这个线程id记录下来,记录为偏向锁,如果有另一个线程来竞争锁的时候,先看自己偏向锁的线程id是不是自己的id,如果是那么直接进入,如果不是,那么就自旋等待+CAS,尝试将自己的线程Id写入,如果自旋结束没有写入成功,那么到了全局安全点,就会升级为轻量级锁,两个线程内部都有一个 record word 称为锁记录,两个线程尝试将markword拷贝到自己的锁记录中,并采用CAS的方式尝试将指针指向自己。如果修改成功,那么就代表此线程获取到锁。如果出现多个线程来尝试获取锁,那么说明对象锁竞争激烈,就会升级为重量级锁。

自旋锁的特点是等待线程并没有切换出CPU资源,而是使用自循环的方式将自己保持在CPU的L1/L2缓存中,这样就避免了线程在CPU的切换过程。实际上并没有真正开启Object Monitor机制,所以不会反映在对象头中

当对象的锁级别升级为重量级锁的时候,JVM就开始采用Object Monitor机制控制各线程去抢占对象。实际上是JVM对操作系统级别互斥锁的管理过程

操作系统中对进程同步的方式有互斥量,信号量,管程

关于重量级锁,个人理解为在操作系统级是称为管程[引入:如果互斥量是人为控制,比较容易引起死锁,所以提出这个比较高层的原语],在语言层面有的实现了,有的没有实现。

java中的监视器就是管程的一种实现

管程就是管理进程

监视区域相当于一个原子区域,JVM保证了同时只能有一个线程在执行,监视区域前后有入口区域和等待区域,其进出原则:

1.如果一个线程访问监视区域,如果监视区域没有线程,那么直接进入

2.如果有线程,那么就在入口区域等待

3.监视区域的线程可以通过命令进入等待区域,等待区域的可以通过命令唤醒重新进去入口区域等待,但是等待线程并不是唤醒后就直接醒来,当唤醒线程执行结束后退出监视区域后,等待线程才会醒来。

moniter理解更是一种机制:

1.临界区

2.对象和锁

3.条件变量以及定义在moniter对象上的wait,notify操作
操作系统中对进程同步的方式有互斥量,信号量,管程

posted @ 2020-08-31 17:29  多放点香菜  阅读(165)  评论(0)    收藏  举报