前言
关于Java锁细节的博客,蛮受读者欢迎的。也有许多不足,比如排版,一些细节等。Java锁细节与锁之编程细节讲述锁的两个不同方面,所以分开写。Java锁细节是讲述每种锁的细节,把锁当做人的话,讲述的是男人,女人,大人,小孩的细节。锁之编程细节讲述的如高性能的使用锁。如同让人怎么跑得块而已。
大纲
编程细节如下:
- 锁粗化
- 锁细化
- 保证public方法线程安全
- 分段锁
主体
关于锁粗化与锁细化,在很多关于java优化的书籍都会讲解。比如java并发编程(是老胡并发与锁的启蒙书)等等。一些读者在读Java锁细节说没有讲解锁粗化。在大家的要求,老胡只能厚着面皮写下本博客了。
大家是否觉得十分绕口,锁粗化,锁细化在名词上是两个对立的。为什么都是优化的方法了?其实可以想象成长跑,短跑。就好了。
锁粗化
- 把多次的锁合并成一个锁,减少锁消耗,提升执行性能
- 在高并发的情况下,减少锁竞争。
receiveIntegerNoLock 方法调用了两个声明synchronized的方法。
public IntegeralInfo receiveIntegerNoLock(Integer addIntegeral) {
addIntegeral(addIntegeral);
addReceiveNum();
return this;
}
/**
* 增加积分
*
* @param addIntegeral
*/
public synchronized void addIntegeral(Integer addIntegeral) {
this.integeralValue += addIntegeral;
}
/**
* 增加签到次数
*/
public synchronized void addReceiveNum() {
this.receiveNum++;
}
新的receiveInteger方法声明了synchronized。值使用了一个锁
public synchronized IntegeralInfo receiveInteger(Integer addIntegeral) {
this.integeralValue += addIntegeral;
this.receiveNum++;
return this;
}
锁细化
- 只对需要数据安全的操作上锁。减少锁占用时间。从而提升并发性能
- 使用。vm会对进行优化。锁范围为少,优化越好
需求,通过连续签到的天数,计算当次签到应得到多少积分,把计算出的积分增加到用户积分上,并计算除等级。
分析如下
- 需要通过连续签到天数,计算当次签到应得到多少积分
- 把计算出的积分增加到用户积分上
- 并计算除等级
案例
public synchronized void continuityReceiveIntegeralAlsoGradeSynchronized(Integer continuityDate) {
// 通过天数计算,应该获得多少积分
int addIntegeral = calculationSignIntegeral(continuityDate);
// 添加积分
this.integeralValue += addIntegeral;
// 计算等级
gradeCalculation();
}
public int calculationSignIntegeral(Integer continuityDate) {
return continuityDate/1;
}
/**
* 等级计算
*/
private void gradeCalculation() {
}
最简单的实现,没有进行任何的优化。三个操作的代码放到一个方法里面。观察calculationSignIntegeral方法会发现,只是进行数据计算,是一个安全的方法,可以不用上锁。gradeCalculation方法在一定程度上也是安全的方法,未实现。这个需求有点复杂,不知道那个大神,可以分析出来,并实现。
优化之后的是
public void continuityReceiveIntegeralAlsoGrade(Integer continuityDate) {
// 通过天数计算,应该获得多少积分
int addIntegeral = calculationSignIntegeral(continuityDate);
// 添加积分
synchronized (this) {
this.integeralValue += addIntegeral;
}
// 计算等级
gradeCalculation();
}
只对需要上锁的计算出的积分增加到用户积分上操作进行上锁,减少的上锁范围。缩短持有锁的时间,从而提高并发性能
public都是线程安全
java api里面的类,个个都写得十分优秀。是学习,深入,理解基础技术的优质的代码。解读java.util.Hashtable的源码,从而理解public都是线程安全,而非public方法都是线程不安全的。当你看完java.util.Hashtable源码会发现,所有的public都是线程安全,而非public方法都是线程不安全的。
public都是线程安全,而非public方法都是线程不安全的。这种设计有一下特性
- 一种优秀的编码规范,方法层次十分明显,强大的可读性。减少开发成本,维护成本,理解成本,容易定位问题。
- 所有public方法的实现只能为锁粗化。
- public方法内没有具体的实现,只负责调用private方法。private负责具体的实现。这是一种开闭原则的具体实现。
开闭原则(OCP)是面向对象设计中“可复用设计”的基石,是面向对象设计中最重要的原则之一,其它很多的设计原则都是实现开闭原则的一种手段。对于扩展是开放的,对于修改是关闭的,这意味着模块的行为是可以扩展的
分段锁
按照算法计算出的结果或者数据特性进行分类,分类中的每个类型都有一把锁。可以减少锁争夺,更高并行度。
关于分段锁最简单的实现还是在java api中,jdk6的ConcurrentHashMap。 ConcurrentHashMap通过hash算法得到key的hash值,在与数组长度求余,余数是数组下标。下标就是分类的类型 下面链接是一个大神写的关于jdk6的ConcurrentHashMap源码解读,写得有点乱,但是解读得十分详细。请点击
完整代码
public class LockUser {
static class IntegeralInfo {
// 用户积分
private Integer integeralValue;
// 经验值
private Integer experienceValue;
// 签到
private Integer receiveNum;
// 等级
private Integer grade;
/**
* 添加积分,同时增加签到次数
*
* @param addIntegeral
* 需要添加的积分
* @return
*/
public synchronized IntegeralInfo receiveInteger(Integer addIntegeral) {
this.integeralValue += addIntegeral;
this.receiveNum++;
return this;
}
public IntegeralInfo receiveIntegerNoLock(Integer addIntegeral) {
addIntegeral(addIntegeral);
addReceiveNum();
return this;
}
/**
* 增加积分
*
* @param addIntegeral
*/
public synchronized void addIntegeral(Integer addIntegeral) {
this.integeralValue += addIntegeral;
}
/**
* 增加签到次数
*/
public synchronized void addReceiveNum() {
this.receiveNum++;
}
public synchronized void continuityReceiveIntegeralAlsoGradeSynchronized(Integer continuityDate) {
// 通过天数计算,应该获得多少积分
int addIntegeral = calculationSignIntegeral(continuityDate);
// 添加积分
this.integeralValue += addIntegeral;
// 计算等级
gradeCalculation();
}
public void continuityReceiveIntegeralAlsoGrade(Integer continuityDate) {
// 通过天数计算,应该获得多少积分
int addIntegeral = calculationSignIntegeral(continuityDate);
// 添加积分
synchronized (this) {
this.integeralValue += addIntegeral;
}
// 计算等级
gradeCalculation();
}
public int calculationSignIntegeral(Integer continuityDate) {
return 1;
}
/**
* 等级计算
*/
private void gradeCalculation() {
}
}
}