在項目開發中 或許會碰到JAVA的多線程處理 為保證業務數據的正常 必須加上鎖機制 常用的處理方法一般是加上synchronized關鍵字 目前JDK版本對synchronized已經做了很好的優化 我們不用再考慮其性能 但在實際使用中 往往由於處理不當 導致系統性能的嚴重下降 那麼該如何合理的使用synchronized 必須對其使用方式有個全面了解 在網上搜尋的資料 給出的是四種使用方式 其實可總結為兩種 一個是同步代碼塊 一個是同步方法體 那麼該如何使用 請看下面的測試
准備兩個方法 對同一個變量做加法 再對每個方法 分別開十個線程執行
[java]
public class ThreadUnit
{
private int i = ;
private Object obj = new Object()
private Object obj = new Object()
public synchronized Integer doAdd(Long start) throws Exception
{
Threadsleep()
++i;
Threadsleep()
return i;
}
public Integer doAdd(Long start) throws Exception
{
Threadsleep()
++i;
Threadsleep()
return i;
}
}
相關代碼
[java]
// 十個線程同時執行方法
for (int i = ; i < ; i++)
{
new Thread(new MessageThread( threadUnit))start()
}
// 十個線程同時執行方法
for (int j = ; j < ; j++)
{
new Thread(new MessageThread( threadUnit))start()
}
線程處理
[java]
public void run()
{
try
{
if (operate == )
{
long start = SystemcurrentTimeMillis()
int i = threadUnitdoAdd(start)
long takeTime = SystemcurrentTimeMillis() start;
Systemoutprintln(doAdd() => i= + i + spendTime= + takeTime + ms)
spendTime += takeTime;
}
else
{
long start = SystemcurrentTimeMillis()
int i = threadUnitdoAdd(start)
long takeTime = SystemcurrentTimeMillis() start;
Systemoutprintln(doAdd() => i= + i + spendTime= + takeTime + ms)
spendTime += takeTime;
}
}
catch (Exception e)
{
eprintStackTrace()
}
}
運行結果
在兩個方法體上都加上synchronized
[java]
public synchronized Integer doAdd(Long start) throws Exception
[java]
public synchronized Integer doAdd(Long start) throws Exception
執行結果
[html]
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
花費時間ms
都是有序執行 變量值沒有產生錯亂 但花費時間ms
在doAdd方法上加上synchronized doAdd不加
[java]
public synchronized Integer doAdd(Long start) throws Exception
執行結果
[java]
doAdd方法加上synchronized:
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
花費時間ms
doAdd方法瞬間執行完成 之後doAdd方法則是串行有序執行 這時doAdd方法獲取的變量值已經錯亂 doAdd獲取的正常 花費時間ms
兩個方法在都沒使用synchronized前的情況
執行結果
[java]
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
花費時間ms
可以看到 兩個方法的變量值獲取已經錯亂 但花費時間最少ms
使用同步塊 在兩個方法內采用不同的對象鎖
doAdd:
[java]
synchronized (obj)
{
Threadsleep()
++i;
Threadsleep()
return i;
}
doAdd:
[java]
synchronized (obj)
{
Threadsleep()
++i;
Threadsleep()
return i;
}
執行結果
[html]
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
花費時間ms
兩個方法有序交替執行 互不影響 花費時間ms 相對加鎖同一對象執行的時間縮短
使用同步塊 使用方法參數作為對象鎖
[java]
public Integer doAdd(Long start) throws Exception
{
synchronized (start)
{
Threadsleep()
++i;
Threadsleep()
return i;
}
}
執行結果
[java]
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
花費時間ms
執行效果和第三種情況相同 每個參數作為不同的對象 即便加上synchronized也不能起到鎖的效果
把調用的類改為靜態類 只在一個方法上加鎖
加鎖doAdd方法
[java]
public static synchronized Integer doAdd(Long start) throws Exception
執行結果
[html]
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
doAdd() => i= spendTime=ms
花費時間ms
和第二種情形類似 沒有加鎖的doAdd方法瞬間執行完成 doAdd方法則是串行有序執行
總結
synchronized關鍵在於鎖定的對象 如果是同一對象 那麼所有執行線程 必須等待對象鎖釋放後才能執行 如果是不同對象 那麼只對各對象所關聯的線程生效
synchronized若加在方法體上 默認鎖定的是對象本身 對於所有加鎖的方法 都是按照串行規則有序執行 對於沒有加鎖的方法 不受任何影響 靜態類同理
合理使用synchronized 既要保證穩定性 又要保證性能 需要在兩者間作出權衡 盡量把synchronized范圍細度化 合理控制業務處理流程 對象操作原子化 減少鎖的使用
不要盲目在方法體上加synchronized關鍵字 如果每個方法負責處理的是不同業務 那麼盡量采用第四種情形 使用不同的對象鎖處理 而不是鎖定整個對象
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27586.html