java锁(转)
Java中锁分类
锁的分类
CAS
它是解决轻微冲突的多线程场景下使用锁造成性能损耗的一种机制
。先是比较
,如果不符合预期,则重试
。它有三个操作因素:内存位置
,预期原值
与新值
。如果内存位置的值与预期原值相等,则处理器将该位置值更新为新值,如果不相等,则获取当前值,然后进行不断的轮询操作直到成果达到某个阙值退出。
AQS
AbstractQueuedSynchronizer
简称AQS是一个抽象同步框架,可以用来实现一个依赖状态的同步器。JDK1.5中提供的java.util.concurrent
包中的大多数的同步器(Synchronizer)
如Lock, Semaphore, Latch, Barrier
等,它们都是基于java.util.concurrent.locks.AbstractQueuedSynchronizer
这个类的框架实现的。
乐观锁/悲观锁
乐观锁
:乐观锁是一种乐观思想,认为读多写少
,遇到并发的可能性低,每次拿数据时候并不会上锁
,因为认为不会被别人修改。但是更新的时候会判断有没有人会更新这条数据,采取写的时候先读取版本号然后加锁
,主要是和上一次版本号进行比较
,如果一样则更新这条数据,如果不一样则会重复读,比较,写操作。它是基于CAS
来实现的。悲观锁
:悲观思想,认为写多读少
,遇到并发写可能性比较高,每次读写数据都会上锁,别的线程想要读写只会被阻塞住直到拿到锁。java中的悲观锁就是Synchronized
,AQS(AbstractQueuedSynchronizer)
框架下的锁则是先尝试cas乐观锁去获取锁,获取不到,才会转换为悲观锁,如RetreenLock
。
公平锁与非公平锁
公平锁:指的是多个线程按照申请锁的顺序来获取锁。
非公平锁:多个线程并不是按照申请锁的顺序获取锁,有可能后申请的比先申请的线程优先获取锁,可能造成饥饿现象,也就是线程无法访问资源而出现无法执行下去的现象。
RetreenLock
它是通过构造函数来确定是不是公平锁,默认是非公平锁。非公平锁的吞吐量比公平锁大。而Synchronized
是非公平锁,它没有通过AQS实现线程调度,无法成为公平锁。//默认创建是非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
//通过bool值来控制是否是公平的还是不公平的,为true公平锁,为false不公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
可重入锁
- 也称为递归锁,线程可以重复获取一把锁,同一个线程在外层方法获取锁,进入内层方法会自动获取锁。
synchronized
和ReentrantLock
都是可重入锁,可重入锁在一定程度上可以避免死锁。
独享锁与共享锁
- 独享锁指的是锁一次只能被一次线程持有
- 共享锁同时可以被多个线程持有
synchronized
和ReentrantLock
都是独享锁,ReadWriteLock
的读锁是共享锁,写锁是独享锁;ReentrantLock
的独享锁和共享锁也是通过AQS
来实现的。
互斥锁与读写锁
- 其实是独享锁与共享锁具体说法;互斥锁Java中实现就是
ReentrantLock
,而读写锁Java实现是ReadWriteLock
。
分段锁
- 实质上是一种锁的
策略
,并不是具体的锁。对于ConcurrentHashMap
它的并发实现在JDK 11之前是都过分段锁来实现的。当需要put元素时候,并不是对hashMap整个加锁,而是通过hashCode知道在那个分段,进行分段加锁。在多线程操作中,只要put元素时候不放在同一个分段区域中,就可以进行并行插入元素,统计大小时候需要获取所有分段锁。归根结底分段锁是用来细化锁的粒度。
偏向锁
- 从始至终只要一个线程请求一把锁。同步代码一直被一个线程访问,线程自动获取锁。 Java偏向锁是Java6引入的一项多线程优化。它会偏向第一个访问锁的线程,如果运行过程中,只有一个线程访问,没有多线程争用情况,则线程无需同步,这时候线程就会被加一个偏向锁。 但是再运行的时候,遇到其他线程占锁,则持有偏向锁的线程会被挂起,并且JVM会消除它身上的偏向锁,将锁升级为轻量级锁。
偏向锁适用场景
- 始终只有一个线程在执行同步代码块,在它没有执行完成前,没有其他线程去执行,锁没有竞争,但是有了竞争,就会升级为轻量级锁。这时候升级的轻量级锁如果撤销的话,会触发
stop the world
操作。
stop the world 简介
- Java中
Stop-The-World
机制简称STW,是在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)。Java中一种全局暂停现象,全局停顿,所有Java代码停止,native
代码可以执行,但不能与JVM交互。
轻量级锁
- 是由偏向锁升级而来,偏向锁时候,一个线程进入同步代码块,这时候另一个线程加入锁的争用,它就会升级为轻量级锁。 多个线程在不同时间段请求同一把锁,也就是没有竞争的情况下,Java虚拟机就会采用轻量级锁,来避免重量级锁阻塞以及重复唤醒。
轻量级锁释放
- 当轻量级锁在释放的期间,会由轻量级锁切换到重量级锁,之前在获取锁的时候它拷贝的对象头markWord,在释放锁的时候它发现自己持有锁的时被其他线程访问,并且此线程对markword进行了修改,两者对比发现不一致就切换到重量级锁。
重量级锁
- 它是Java中的基础锁,在这种状态下,Java虚拟机会阻塞加锁失败的线程,并且在目标锁被释放的时候,唤醒这些线程。Java中
synchronized
就是一种重量级锁。 当轻量级锁在释放的期间,会由轻量级锁切换到重量级锁,之前在获取锁的时候它拷贝的对象头mark Word,在释放锁的时候它发现自己持有锁的时被其他线程访问,并且此线程对mark word进行了修改,两者对比发现不一致就切换到重量级锁。重量级锁会让其他申请的线程进入阻塞,性能降低。
什么是Java对象头
- Java对象头包括两部分信息,分别是
Mark Word
与元数据指针,Mark Word
用于存储对象运行时的数据,比如HashCode
、锁状态标志、Gc分代年龄、线程持有的锁等,而元数据指针用于指向方法区中的目标类的元数据,通过元数据可以确定对象的具体类型。
自旋锁
- 当持有锁的线程能够在很短的时间内释放锁,而那些等待竞争锁的线程就无需做内核态与用户态之间的切换进入阻塞挂起状态,它们只需要等一等,自旋,等持有锁的线程释放锁后可以立即获取锁,减少了线程上下文切换。但是会循环造成CPU消耗增加。
解决自选锁CPU浪费
- 如果锁的竞争激烈,或者持有锁的线程需要长时间占用锁执行同步块,这时候就不适合使用自旋锁了,因为自旋锁在获取锁前一直都是占用cpu做无用功,占着CPU却不用,并且这个时候有大量线程在竞争一个锁,会导致获取锁的时间很长,线程自旋的消耗大于线程阻塞挂起操作的消耗,其它需要cup的线程又不能获取到cpu,造成cpu的浪费。所以这种情况下我们要关闭自旋锁;
原文引自https://cloud.tencent.com/developer/article/1560084
java锁(转)的更多相关文章
- java 锁!
问题:如何实现死锁. 关键: 1 两个线程ta.tb 2 两个对象a.b 3 ta拥有a的锁,同时在这个锁定的过程中,需要b的锁:tb拥有b的锁,同时在这个锁定的过程中,需要a的锁: 关键的实现难点是 ...
- Java锁(一)之内存模型
想要了解Java锁机制.引发的线程安全问题以及数据一致性问题,有必要了解内存模型,机理机制了解清楚了,这些问题也就应声而解了. 一.主内存和工作内存 Java内存模型分为主内存和工作内存,所有的变量都 ...
- Java锁的种类
转载自:---->http://ifeve.com/java_lock_see/ Java锁的种类以及辨析锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchroniz ...
- JAVA 锁
JAVA 锁 锁的概念 Java中的锁是控制资源访问的一种方式.它弥补了synchronized的可操作性不强的不足. Java的锁都实现了Lock接口.Lock结构定义了锁的基本操作. 函数 解释 ...
- JAVA锁的可重入性
机制:每个锁都关联一个请求计数器和一个占有他的线程,当请求计数器为0时,这个锁可以被认为是unhled的,当一个线程请求一个unheld的锁时,JVM记录锁的拥有者,并把锁的请求计数加1,如果同一个线 ...
- JAVA 锁之 Synchronied
■ Java 锁 1. 锁的内存语义 锁可以让临界区互斥执行,还可以让释放锁的线程向同一个锁的线程发送消息 锁的释放要遵循 Happens-before 原则(锁规则:解锁必然发生在随后的加锁之前) ...
- java锁与监视器概念 为什么wait、notify、notifyAll定义在Object中 多线程中篇(九)
在Java中,与线程通信相关的几个方法,是定义在Object中的,大家都知道Object是Java中所有类的超类 在Java中,所有的类都是Object,借助于一个统一的形式Object,显然在有些处 ...
- 自己动手写java锁
1.LockSupport的park和unpark方法的基本使用,以及对线程中断的响应性 LockSupport是JDK中比较底层的类,用来创建锁和其他同步工具类的基本线程阻塞原语.java锁和同步器 ...
- Java 锁的学习
个人学习整理,所有资料均来源于网络,非原创. 死锁的四个必要条件:互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用.请求与保持条件(Hold and wait):已经得 ...
- java锁——wait,notify,synchronized
背景:这篇博客用来总结java锁相关的知识点,平时还是要自己多加练习 wait 和 notify以及notifyAll (1).方法介绍1.wait.notify以及notifyAll都是Object ...
随机推荐
- 《手把手教你构建自己的 Linux 系统》学习笔记(4)
汇编链接器(Binutils) 这是一个软件包,这个软件包其实是一个工具集,里面含有了大量的用于汇编程序活着读取二进制文件相关的程序. CC 它是一条命令的别名,这条命令的作用是使用 GCC 的 C ...
- P3945 | 三体问题 (天体物理+计算几何)
最近终于把<三体Ⅰ·地球往事>和<三体Ⅱ·黑暗森林>看完了! 为了快点认识题目中的歌者文明,已经开始第三部了! 题目背景 @FirstLight0521 出题人在这里哦~ 三体 ...
- DOM基础+domReady+元素节点类型判断
DOM节点类型 nodeType element 1 Node.ELEMENT_NODE 元素节点 attr 2 Node.ATTRIBUTE_NODE 属性节点 text 3 ...
- sqlserver2014部署安装
百度云网址链接: https://pan.baidu.com/s/1BwgdnESI8Fqlos9EIOLv1A 提取码: wsy5 1.解压ISO镜像文件,点击setup安装程序 2.进入安装界面 ...
- maven的核心概念——坐标
7.1 几何中的坐标 [1]在一个平面中使用x.y两个向量可以唯一的确定平面中的一个点. [2]在空间中使用x.y.z三个向量可以唯一的确定空间中的一个点. 7.2 Maven的坐标 使用如下三个向量 ...
- contos7命令行访问网址
1.curl访问: 例子: curl http://www.baidu.com 注意:这种访问只会直接读取网站HTML代码出来 2.elinks访问: yum -y install elinks : ...
- 用JavaScript设计和创建对象
通过在优锐课的java学习分享中,get很多学习新技能,分享给大家参考学习. 介绍 在阅读此分步指南之前,你可能需要关注面向对象编程的介绍. 以下步骤中包含的Java代码与该文章理论中使用的Book对 ...
- 剑指offer-面试题29-顺时针打印矩阵-矩阵
/* 题目: 输入一个矩阵,按照从外到内顺时针的顺序依次打印每一个数字. */ /* 思路: 1.将打印矩阵看作是打印一个个从外向内的环. 2.每一个环都有一个起始节点,起始节点的坐标*2小于行数和列 ...
- 剑指offer-面试题10-斐波那契数列-递归循环
/* 题目:求斐波那契数列的第n项 */ /* 思路: f(n) = 0 n=0, 1 n=1, f(n-1) + f(n-2) n>1 */ int Fibonacci(int n){ if( ...
- [CTSC2008]网络管理 [树剖+整体二分]
这题的复杂度可以到达惊人的\(\log^4\)据说还能跑过去(差点没吓死我 直接二分+树剖树套树(\(n \log^4 n\)) 一个\(\log\)也不少的4\(\log\) 但是我有个\(\log ...