synchronized锁

synchronized锁

synchronized锁

对象锁

  • 一个对象一把锁

类锁

判断是同步还是异步关键看是不是同一把锁

  • 锁加在方法上或在方法中写对象是个对象锁
  • 锁加在类上或静态方法上是类锁

synchronized锁的底层实现原理

jvm是基于进入和退出Monitor对象来实现方法同步和代码块同步

代码块的同步

  • 代码块的同步是利用monitorenter和monitorexit这两个字节码指令

    • 分别位于同步代码块的开始和结束位置
  • 当jvm执行到monitorenter指令的时候,试图获取monitor对象的所有权,获取成功锁的计数器+1,当执行到monitorexit的时候,锁计数器-1,当锁计数器=0,锁就被释放,如果获取monitor对象失败,就会进入阻塞的状态

方法级的同步为隐式

  • 不是通过字节码指令来控制,它实现在方法调用和返回之中
  • JVM可以从方法常量池的方法表结构(method_info Structure)的ACC_SYNCHRONIZED 访问标志区分一个方法是否同步方法
  • 当方法调用时,调用指令检查ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,该线程将先持有monitor,然后执行方法,最终方法执行完(无论成功、失败)释放monitor

synchronized锁升级过程

1、无锁状态

2、偏向锁

  • 适合只有一个线程执行同步代码块

    • 当有另外一个线程进来立即转成轻量级锁

3、轻量级锁乐观锁

  • 多个线程竞争偏向锁,偏向锁关闭,升级成重量级锁,中间过程有个锁自旋(1.6引入自适应锁自旋,会根据锁上一次的自旋时间来判断自旋的次数)

4、重量级锁

synchronized锁优化

减少synchronized的范围,同步代码块中的代码尽量少

降低synchronized锁的粒度

  • 尽量不使用同一个锁

分段锁

  • concurrentHashMap:局部锁定
  • hashtable:增删该全部上锁

读写分离,读取时不加锁,写入和删除的时候上锁

锁消除

  • 去除那些不可能发生资源竞争的锁

    • 比如说一些线程安全的集合,默认加了锁,JVM根据逃逸分析进行锁消除

锁粗化

  • 将多个连续的加锁、解锁连在一起,扩成一个更大范围的锁

    • for循环,加锁放在循环外面

1.6引入的自适应锁自旋

  • 根据锁上一次的自旋时间来判断

CAS

定义:在并发量不是很高的情况下,先查一次,然后进行修改,在真正的写数据时,会再查一次,比较两次查询的结果,如果不一样说明是不安全的,如果一样说明安全,会进行修改

在高并发的情况下,会有一个忙循环的过程,消耗cpu

ABA问题

  • 通过维护一个版本号来解决
  • 之前读和过段时间读,可能中间会被第三个人修改过,但是又被改回来

CAS只能针对一个共享变量

ReentrantLock与synchronized的区别

1、从jvm角度来看synchronized其实jvm的一个关键字,ReentrantLock是一个类

2、synchronized不需要关心锁的释放,ReentrantLock需要手动lock利用try..catch..finanlly释放锁

所有线程能够看到共享内存的最新状态

volatile关键字

保证内存的可见性

防止指令重排

  • 防止Jvm继续指令重拍优化
  • PS:单线程下指令重排会考虑数据的依赖性,不会影响执行结果
    2、多线程会有影响

不保证原子性

  • 使用并发包下的Atomic的类

    • 如AtomicInteger.....

PS:底层通过屏障指令保证可见性、有序性,刷新主从的数据

ps:锁是不可逆的,一旦升级成重量级的锁就不变了

lock与synchronized的区别

lock需要手动加锁、释放锁

synchronized在发生异常,会自动释放线程占有锁,不会发生死锁,lock必须将unLock()放到finally{} 中

lock支持实现公平锁(按照加锁的顺序,先来的先拿到锁)和非公平锁,synchronized只支持非公平锁

死锁产生的四个必要条件

互斥条件

  • 在某段时间某个资源被一个线程占用,另外一个线程请求资源,只能等待

请求和保持

  • 进程已至少保持一个资源,又提出了新的资源请求,而其他资源又被占用,此时请求线程阻塞,自己已获取的资源又不能释放

不剥夺条件

  • 自己已获取的资源,在未使用完之前,不能被剥夺,只有使用完才可释放

环路等待条件

  • 发生死锁时,存在进程---资源的环形链

案例

  • Test01.java

synchronized保证内存可见性

image.png

AQS

定义:队列同步器

两种资源共享方式

  • Exclusive

    • 独占,只有一个线程能执行,如ReentrantLock
  • Share

    • 共享,多个线程可同时执行,如Semaphore/CountDownLatch

本质使用CLH的同步队列存放线程资源

  • 先进先出

    • 入列

    • 出列

锁的基本概念

互斥锁

  • 每个对象都对应一个可称为“互斥锁”的标记,保证在任意时刻,只有一个线程可以访问该资源

阻塞锁

  • 让线程进入阻塞状态

自旋锁

读写锁

公平锁

  • 排队,先来先得

非公平锁

  • 不考虑排队问题

ReentrantLock

相比于synchronized性能会好些

互斥锁

  • 同一时间仅有一个线程可以访问,所以就有了ReentrantReadWriteLock读写锁

ReentrantReadWriteLock

  • 读写锁ReentrantReadWriteLock实现接口ReadWriteLock,该接口维护了一对相关的锁,一个用于只
    读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持。写入锁是
    独占的

锁降级

  • 获取写锁-》获取读锁-》释放写锁

JUC

CyclicBarrier

  • 同步屏障

Semaphore

  • 通过已有的信号量,对资源的线程访问数量进行控制,有公平和非公平两种实现方式

CountDownLatch

  • 计数器没到,继续等待,到了0就可以执行了
  • PS:计数无法被重置

atomic包

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容