锁优化
1.减少锁持有时间
如果某个线程持有锁的时间越长,那么锁的竞争程度也就越激烈。
下面所示代码。直接在method1进行了加锁,但是只有方法method2内部需要进行同步操作,将加大锁的持有时间。
public synchronized void method1() {
method2();
method3();
method4();
}
public void method2() {
//同步操作
}
public void method3() {}
public void method4() {}
采用以下方法可以有效减少锁的持有时间。
public void method1() {
synchronized(this) {
method2();
}
method3();
method4();
}
public void method2() {}
public void method3() {}
public void method4() {}
Patter类中matcher方法:只有在表达式未编译时,进行局部加锁。
/**
* Creates a matcher that will match the given input against this pattern.
*
* @param input
* The character sequence to be matched
*
* @return A new matcher for this pattern
*/
public Matcher matcher(CharSequence input) {
if (!compiled) {
synchronized(this) {
if (!compiled)
compile();
}
}
Matcher m = new Matcher(this, input);
return m;
}
2.减小锁粒度
ConcurrentHashMap内部进一步分了默认16个小的HashMap,即16个SEGMENT段。
对于常用的put操作:先根据hashcode得到该新的数据应该被存放到的段,然后只对该段进行加锁,并进行put操作。因此默认、理想情况下,可同时让16个线程同时进行put操作。但如果需要获取它的全局信息,比如size,就需要获取该对象所有段的锁然后进行计算size值。但是ConcurrentHashMap的size()方法并不是总这样获取,事实上,它会先利用无锁方式进行求和,如果失败才会采用上述的加锁方式求值。
3.读写分离锁
用于读多写少的环境下,因为读操作不影响数据的完整性和一致性,可以运行多线程同时对数据进行读操作。
4.锁分离
在队列操作中,take与put方法分别作用于队列的两端进行取、添加数据,互不影响操作。可以分别对他们加锁,进行锁分离。
5.锁粗化
如果某一个锁对同一个锁不停地进行请求、同步和释放,将消耗系统的资源,不利于优化。因此当JVM在遇到一连串地对同一锁不断进行请求和释放的操作时,便会把所有的锁操作整合成对锁的一次请求,从而减少对锁的请求同步次数,称为锁粗化。private ReentrantLock lock = new ReentrantLock();
public void method3() {
int size = 500;
for(int i = 0; i < size ; i++) {
synchronized(lock) {
//doSomething
}
}
}
private ReentrantLock lock = new ReentrantLock();
public void method3() {
int size = 500;
synchronized(lock) {
for(int i = 0; i < size ; i++) {
//doSomething
}
}
}