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 ...
随机推荐
- Eclipse+ADT+Android SDK搭建安卓开发环境
第一步:打开[Android.rar]压缩包,如图所示[评论区回复我,压缩包地址] 第二步:配置环境变量 (1) 解压[android-sdk_r24.4.1-windows.zip]压缩包 (2) ...
- P2094运输
-------------------- 链接:Miku ------------------- 这是一道水贪心,很容易想到做法就是把最贵的两个放在一块,让后当成一个重新放回队列 ---------- ...
- postman设置变量
参数化 变量引用格式:{{username}} , 区别jmeter的 {username} 一.设置与引用环境变量 背景:在不同的环境下跑相同的测试,生产环境或测试环境 二.设置与引用全局变量 ...
- 破解“低代码”的4大误区,拥抱低门槛高效率的软件开发新选择 ZT
最近,每个人似乎都在谈论“低代码”.以美国的Outsystems.Kinvey,以及国内的活字格为代表的低代码开发平台,正在风靡整个IT世界.毕竟,能够以最少的编码快速开发应用的想法本身就很吸引人.但 ...
- eclipse一直不停building workplace
找解决方案的时候自己好了 然后又卡在了updating maven project 暂无解
- P1001 A+B Problem(int,long long)
题目描述 输入两个整数 a,b,输出它们的和(∣a∣,∣b∣≤109). 注意 Pascal 使用 integer 会爆掉哦! 有负数哦! C/C++ 的 main 函数必须是 int 类型,而且最后 ...
- redis的一些常见面试题
1 .在项目中缓存是如何使用的? 2.为啥在项目里要用缓存呢? 用缓存,主要用途,高性能和高并发 高性能: 场景举例:假如有这么一个操作,用户发起请求,操作数据库,查出结果,耗时600ms,然后这个结 ...
- 论文阅读笔记(十四)【AAAI2020】:Appearance and Motion Enhancement for Video-based Person Re-identification
Introduction 本文的贡献:提出了基于视频的行人重识别模型:Appearance and Motion Enhancement Model(AMEM).该模型对两类信息进行提取:提出了App ...
- PHP 计算当前时间是这一年的第几周
$week = intval(date('W',time()));
- 基于单片机的心型LED灯的设计与实现
#include<reg51.h> #include<intrins.h> #define char unsigned char #define unit unsigned i ...