Java锁优化
Java锁优化
应用程序在并发环境下会产生很多问题,通常情况下,我们可以通过加锁来解决多线程对临界资源的访问问题。但是加锁往往会成为系统的瓶颈,因为加锁和释放锁会涉及到与操作系统的交互,会有很大的性能问题。那么这个时候基于锁的优化手段就显得很重要了。
一般情况下,可以从两个角度进行锁优化:对单个锁算法的优化和对锁粒度的细分。
1. 单个锁的优化
自旋锁:
非自旋锁在未获取锁的情况会被阻塞,之后再唤醒尝试获得锁。而JDK的阻塞和唤醒是基于操作系统实现的,会有系统资源的开销。自旋锁就是线程不停地循环尝试获得锁,而不会将自己阻塞,这样不会浪费系统的资源开销,但是会浪费CPU的资源。所有现在的JDK大部分都是先自旋等待,如果自旋等待一段时间之后还没有获取到锁,就会将当前线程阻塞。
锁消除:
当JVM分析代码时发现某个方法只被单个线程安全访问,而且这个方法是同步方法,那么JVM就会去掉这个方法的锁。
单个锁优化的瓶颈:
对单个锁优化的效果就像提高单个CPU的处理能力一样,最终会由于各个方面的限制而达到一个平衡点,到达这个点之后优化单个锁的对高并发下面锁的优化效果越来越低。所以将一个锁进行粒度细分带来的效果会很明显,如果一个锁保护的代码块被拆分成两个锁来保护,那么程序的效率就大约能够提高到2倍,这个比单个锁的优化带来的效果要明显很多。常见的锁粒度细分技术有:锁分解和锁分段
2. 细分锁粒度
细分锁粒度的目的是降低竞争锁的概率。
2.1 锁分解
锁分解的核心是将无关的代码块,如果在一个方法中有一部分的代码与锁无关,一部分的代码与锁有关,那么可以缩小这个锁的返回,这样锁操作的代码块就会减少,锁竞争的可能性也会减少
缩小锁的范围
缩小锁的范围是指尽量只在必要的地方加锁,不要扩大加锁的范围,就拿单例模式举例,范围大的锁可能将整个方法都加锁了:
class Singleton {
private Singleton instance;
private Singleton() {
}
// 将整个方法加锁
public synchronized Singleton getInstance() {
try {
Thread.sleep(1000); //do something
if(null == instance)
instance = new Singleton();
} catch (InterruptedException e) {
e.printStackTrace();
}
return instance;
}
}
优化后的,只将部分代码加锁:
class Singleton {
private Singleton instance;
private Singleton() {
}
public Singleton getInstance() {
try {
Thread.sleep(1000); //do something
// 只对部分代码加锁
synchronized(this) {
if(null == instance)
instance = new Singleton();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return instance;
}
}
减少锁的粒度
减少锁的粒度是指如果一个锁需要保护多个相互独立的变量,那么可以将一个锁分解为多个锁,并且每个锁保护一个变量,这样就可以减少锁冲突。看一下下面的例子:
class Demo{
private Set<String> allUsers = new HashSet<String>();
private Set<String> allComputers = new HashSet<String>();
//公用一把锁
public synchronized void addUser(String user){
allUsers.add(user);
}
public synchronized void addComputer(String computer){
allComputers.add(computer);
}
}
缩小锁的粒度后,将一个锁拆分为多个:
class Demo{
private Set<String> allUsers = new HashSet<String>();
private Set<String> allComputers = new HashSet<String>();
//分解为两把锁
public void addUser(String user){
synchronized (allUsers){
allUsers.add(user);
}
}
public void addComputer(String computer){
synchronized (allComputers){
allComputers.add(computer);
}
}
}
如上的方法把一个锁分解为2个锁时候,采用两个线程时候,大约能够使程序的效率提升一倍。
2.2 锁分段
锁分段和缩小锁的粒度类似,就是将锁细分的粒度更多,比如将一个数组的每个位置当做单独的锁。JDK8以前ConcurrentHashMap就使用了锁分段技术,它将散列数组分成多个Segment,每个Segment存储了实际的数据,访问数据的时候只需要对数据所在的Segment加锁就行。
参考:
Java锁分解锁分段技术: http://guochenglai.com/2016/06/04/java-concurrent4-java-subsection-decompose/
ConcurrentHashMap的锁分段技术:https://blog.csdn.net/yansong_8686/article/details/50664351
Java锁优化的更多相关文章
- Java 锁优化
一.重量级锁 Java中,Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的.但是监视器锁本质又是依赖于底层的操作系统的Mutex Lock来实现的.而操作系统实现 ...
- 深入理解java虚拟机(7)---线程安全 & 锁优化
关于线程安全的话题,足可以使用一本书来讲解这些东西.<Java Concurrency in Practice> 就是讲解这些的,在这里 主要还是分析JVM中关于线程安全这块的内容. 1. ...
- Java的锁优化
高效并发是从JDK 1.5到JDK 1.6的一个重要改进,HotSpot虚拟机开发团队在这个版本上花费了大量的精力去实现各种锁优化技术,如适应性自旋(Adaptive Spinning).锁消除(Lo ...
- java多线程编程——锁优化
并发环境下进行编程时,需要使用锁机制来同步多线程间的操作,保证共享资源的互斥访问.加锁会带来性能上的损坏,似乎是众所周知的事情.然而,加锁本身不会带来多少的性能消耗,性能主要是在线程的获取锁的过程.如 ...
- Java并发编程:synchronized和锁优化
1. 使用方法 synchronized 是 java 中最常用的保证线程安全的方式,synchronized 的作用主要有三方面: 确保线程互斥的访问代码块,同一时刻只有一个方法可以进入到临界区 保 ...
- 深入介绍Java中的锁[原理、锁优化、CAS、AQS]
1.为什么要用锁? 锁-是为了解决并发操作引起的脏读.数据不一致的问题. 2.锁实现的基本原理 2.1.volatile Java编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新, ...
- 深入理解Java虚拟机读书笔记9----线程完全与锁优化
九 线程完全与锁优化 1 Java语言中的线程完全 ---线程安全:当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用 ...
- Java 虚拟机对锁优化所做的努力
作为一款公用平台,JDK 本身也为并发程序的性能绞尽脑汁,在 JDK 内部也想尽一切办法提供并发时的系统吞吐量.这里,我将向大家简单介绍几种 JDK 内部的 "锁" 优化策略. 1 ...
- Java并发编程学习:线程安全与锁优化
本文参考<深入理解java虚拟机第二版> 一.什么是线程安全? 这里我借<Java Concurrency In Practice>里面的话:当多个线程访问一个对象,如果不考虑 ...
随机推荐
- WIN10升级失败,故障代码 0X8007042B-0X4000D 解决
个人博客链接:WIN10升级失败,故障代码 0X8007042B-0X4000D 解决
- 针对IE6 7 8当独写样式
IE8的格式: .foot{padding:12px 10px\9;} //在后面加\9 IE7的格式: .foot{*padding:12px 10px\9;} //在前面加* IE6的格式: .f ...
- 转载一篇有关于diff的文章,方便以后复习
本文章是转载的,为了方便以后复习,特地记录一下.他人请去原地址观看!!! 文章原地址:http://www.ruanyifeng.com/blog/2012/08/how_to_read_diff.h ...
- 注解Annotation原理详解及其应用示例
一.什么是注解 注解也叫元数据,例如我们常见的@Override和@Deprecated,注解是JDK1.5版本开始引入的一个特性,用于对代码进行说明,可以对包.类.接口.字段.方法参数.局部变量等进 ...
- Qemu: User mode emulation and Full system emulation
转载: https://wiki.edubuntu.org/UbuntuDevelopment/Ports QEMU QEMU is a processor emulator and supports ...
- Octave基本语法
基本运算 octave:3> 5+6 ans = 11 octave:4> 3-2 ans = 1 octave:5> 8*9 ans = 72 octave:6> 8/4 a ...
- Java基础 - Map接口的实现类 : HashedMap / LinkedHashMap /TreeMap 的构造/修改/遍历/ 集合视图方法/双向迭代输出
Map笔记: import java.util.*; /**一:Collection接口的 * Map接口: HashMap(主要实现类) : HashedMap / LinkedHashMap /T ...
- vue-cli3 将自己写的组件封装成可引入的js文件
一.调整项目结构 首先用 vue-cli 创建一个 default 项目 // 顺便安利一篇文章<Vue 爬坑之路(十二)—— vue-cli 3.x 搭建项目> 当前的项目目录是这样的: ...
- Java集合--Map总结
转载请注明出处:http://www.cnblogs.com/skywang12345/admin/EditPosts.aspx?postid=3311126 第1部分 Map概括 (01) Map ...
- Ellipsis对象
Ellipsis对象. 写作 : ‘…’ 中文解释:省略 该对象bool测试是为真 用途: 1.用来省略代码,作用类似于pass的一种替代方案,这是python的’TBD’(未确定内容). def f ...