java线程中的锁

作者: 小蜗牛Aaron | 来源:发表于2020-01-24 23:19 被阅读0次

java中的锁的概念

自旋锁: 是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。
乐观锁: 假定没有冲突,在修改数据时如果发现数据和之前获取的不一致,则读最新数据,修改后重试修改。
悲观锁: 假定会发生并发冲突,同步所有对数据的相关操作,从读数据就开始上锁。
独享锁(写):给资源加上写锁,线程可以修改资源,其他线程不能再加锁; (单写)
共享锁(读): 给资源加上读锁后只能读不能改,其他线程也只能加读锁,不能加写锁; (多读)
可重入锁、不可重入锁: 线程拿到一把锁之后,可以自由进入同一把锁所同步的其他代码。
公平锁、非公平锁: 争抢锁的顺序,如果是按先来后到,则为公平。

同步关键字

1、用于实例方法、静态方法时,隐式指定锁对象
2、用于代码块时,显示指定锁对象
3、锁的作用域:对象锁、类锁、分布式锁
4、引申:如果是多个进程,怎么办?
特性: 可重入、独享、悲观锁
特殊优化 : 锁消除 (开启锁消除的参数:-XX:+DoEscapeAnalysis -XX:+EliminateLocks) 、锁粗化 JDK做了锁粗化的优化, 但我们自己可从代码层面优化

同步关键字的原理

默认情况下JVM锁会经历:未锁定->偏向锁 -> 轻量级锁 -> 重量级锁 这四个状态

轻量级锁

在未锁定的状态下,可以通过CAS来抢锁,抢到的是轻量级锁。


image.png

重量级锁

轻量级锁中的自旋有一定的次数限制,超过了次数限制,轻量级锁升级为重量级锁。


image.png

偏向锁

在JDK6 以后,默认已经开启了偏向锁这个优化,通过JVM 参数 -XX:-UseBiasedLocking 来禁用偏向锁若偏向锁开启,只有一个线程抢锁,可获取到偏向锁

锁升级的过程

image.png

偏向标记第一次有用,出现过争用后就没用了。 -XX:-UseBiasedLocking 禁用使用偏置锁定,偏向锁,本质就是无锁,如果没有发生过任何多线程争抢锁的情况,JVM认为就是单线程,无需做同步(jvm为了少干活:同步在JVM底层是有很多操作来实现的,如果是没有争用,就不需要去做同步操作)

重量级锁 - 监视器

修改mark word如果失败,会自旋CAS一定次数,该次数可以通过参数配置:超过次数,仍未抢到锁,则锁升级为重量级锁,进入阻塞

monitor也叫做管程,计算机操作系统原理中有提及类似概念。一个对象会有一个对应的monitor。

image.png

wait/notify机制

wait方法导致当前线程等待,加入该对象的等待集合中,并且放弃当前持有的对象锁。notify/notifyAll方法唤醒一个或所有正在等待这个对象锁的线程。
注意:
1、只能在synchronized关键字中使用,且调用wait、notify的对象与锁对象相同,否则会抛出IllegalMonitorStateException异常。
2、wait() 方法调用后,会破坏原子性。

锁的本质

场景:土豪小区车位紧张,只有0357车位还未出售 此时,此时大家都想买0357车位买了0357车位,才能在这儿停车 (加锁)跟小区签订合同后,你就具备了停车0357的资格就说你获得了锁会有一把车位锁,来象征你的0357车位停车资格。

locks包 类层次结构

image.png

void lock(); 获取锁(不死不休)
boolean tryLock(); 获取锁(浅尝辄止)
boolean tryLock(long time, TimeUnit unit) throws InterruptedException; 获取锁(过时不候)
void lockInterruptibly() throws InterruptedException; 获取锁(任人摆布)
void unlock(); 释放锁
Condition newCondition();
结论:
1、lock()最常用;
2、lockInterruptibly()方法一般更昂贵,有的impl可能没有实现lockInterruptibly(),
只有真的需要效应中断时,才使用,使用之前看看impl对该方法的描述。

Reentrantlock

image.png

Condition

用于替代wait/notify。
Object中的wait(),notify(),notifyAll()方法是和synchronized配合使用的,可以唤醒一个或者全部(单个等待集);
Condition是需要与Lock配合使用的,提供多个等待集合,更精确的控制(底层是park/unpark机制);


image.png

同步关键字VS lock

Synchronized

  • 优点:
    1、使用简单,语义清晰,哪里需要点哪里。
    2、由JVM提供,提供了多种优化方案(锁粗化、锁消除、偏向锁、轻量级锁) 3、锁的释放由虚拟机来完成,不用人工干预,也降低了死锁的可能性
  • 缺点:
    无法实现一些锁的高级功能如:公平锁、中断锁、超时锁、读写锁、共享锁等

lock
优点:
1、所有synchronized的缺点
2、可以实现更多的功能,让synchronized缺点更多

  • 缺点:
    需手动释放锁unlock,新手使用不当可能造成死锁

ReadAndWrite Lock

维护一对关联锁,一个只用于读操作,一个只用于写操作;
读锁可以由多个读线程同时持有,写锁是排他的。同一时间,两把锁不能被不同线程持有。

适合读取操作多于写入操作的场景,改进互斥锁的性能,比如:集合的并发线程安全性改造、缓存组件。

锁降级指的是写锁降级成为读锁。持有写锁的同时,再获取读锁,随后释放写锁的过程。
写锁是线程独占,读锁是共享,所以写->读是降级。(读->写,是不能实现的)

相关文章

  • java并发

    1.并发编程中的锁 并发编程中的各种锁java高并发锁的3种实现Java并发机制及锁的实现原理 2.线程池核心线程...

  • 锁的优化

    在前几天的文章:浅谈Java中的锁:Synchronized、重入锁、读写锁 中我们学习了多线程环境下为了保证线程...

  • 深入理解Java中的锁(一)

    Java中锁的概念 自旋锁 : 是指当一个线程在获取锁的时候,如果锁已经被其他线程获取,那么该线程将循环等待,然后...

  • JAVA高并发(三)

    JAVA中的线程同步机制: 在java中,按照锁的实现方式划分为两种, 内部锁:synchronized 显示...

  • java线程中的锁

    java中的锁的概念 自旋锁: 是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后...

  • 关于Redis分布式锁这一篇应该是讲的最好的了,先收藏起来再看!

    前言 在Java并发编程中,我们通常使用到synchronized 、Lock这两个线程锁,Java中的锁,只能保...

  • Java锁相关概念的简单理解

    Java中锁的概念 自旋锁:是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断...

  • java 多线程总结篇4——锁机制

    在开发Java多线程应用程序中,各个线程之间由于要共享资源,必须用到锁机制。Java提供了多种多线程锁机制的实现方...

  • JAVA锁机制

    在开发Java多线程应用程序中,各个线程之间由于要共享资源,必须用到锁机制。Java提供了多种多线程锁机制的实现方...

  • 2019-08-16-Java中实现的锁的区别和简单实现

    Java中实现的锁的区别和实现的原理 在开发Java多线程应用程序中,各个线程之间由于要共享资源,必须用到锁机制。...

网友评论

    本文标题:java线程中的锁

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