鎖優化
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
}
}
}
6.總結