剛學java的時候,僅僅知道synchronized一個線程鎖。能夠鎖住代碼,可是它真的能像我想的那樣,能夠鎖住代碼嗎?
在討論之前先看一下項目中常見關於synchronized的使用方法:
public synchronized void syncCurrentObject() {
System.out.println(Thread.currentThread().getName()+"..start.."+"-----"+System.currentTimeMillis());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"..end.."+"-----"+System.currentTimeMillis());
}
這樣是否能在多個線程訪問時候,保證僅僅有一個線程進入方法。其他線程堵塞嗎?
我用線程池創建三個線程容量,分別啟動五個線程:
public static void syncCurrentObjectTest() {
ExecutorService exec = Executors.newFixedThreadPool(3);
// final GenerateCode gCode = new GenerateCode();
for (int i = 0; i < 5; i++) {
exec.execute(new Runnable() {
@Override
public void run() {
GenerateCode gCode = new GenerateCode();
gCode.syncCurrentObject();
}
});
}
exec.shutdown();
}
運行效果截圖:
依據截圖的輸入日志說明將synchronized加在方法上並不能讓線程安全,而是多個線程並行運行。比方:線程3並沒有等線程1運行完畢后再運行。而是線程1休眠的時候。線程3直接獲得鎖。進行運行。那么在原有的實現上。假設保證線程安全呢?
解決思路:在多個線程調用synchronized修飾的方法時,調用synchronized方法是同一個對象。
詳細解決方式是:將GenerateCode 對象創建一次(寫成單例更好)。然后調用synchronized修飾方法。
詳細改動截圖例如以下:
為什么這樣改就能夠呢?原理是由於對於成員方法。synchronized僅僅能鎖住當前對象的線程,其他對象的線程無法鎖住。
並且synchronized放在方法和在方法內synchronize(this)是等價的。都僅僅能鎖住當前對象。
可是假設想鎖住不同對象的多個線程。該怎么做呢?演示樣例代碼例如以下:
//直接在靜態方法上加synchronized 線程安全
public synchronized static void syncStatic() {
//dosomething..
}
//在靜態方法上synchronized當前類 線程安全
public static void syncCurrentClass() {
synchronized(GenerateCode.class){
//dosomething..
}
}
//在成員方法上synchronized當前類 線程安全
public void syncCurrentObjectByThisClass() {
synchronized(GenerateCode.class){
//dosomething..
}
}
用synchronized鎖住當前類字節碼,當前類中總是僅僅有一個線程能夠進入運行,其他線程進入堵塞。
總結:synchronized能夠鎖當前對象,也能夠鎖類。
synchronized鎖住當前對象的寫法:
public synchronized void a(){
}
public void ab(){
synchronized (this){
}
}
synchronized鎖住當前類的寫法:
public synchronized static void a(){
}
public static void a(){
synchronized (類名){
}
}
public void ab(){
synchronized (類名){
}
}
我的理解是:當synchronized作用在對象時候,同一個對象中的線程是相互排斥的,僅僅有一個線程運行完畢后。另外一個線程才干獲得對象鎖得到運行。
假設不是同一個對象,則不會產生相互排斥
當synchronized作用在類時,對於同一個jvm中不同對象的多個線程調用同一個synchronized修飾的方法都是相互排斥的。由於一個jvm僅僅會產生一個class文件。
拓展:
1、假設想讓線程相互排斥,synchronized方法是否存在效率問題?
理論應該是存在效率問題的,由於每一個對象都有一個對象鎖,當一個線程拿到鎖后,其他線程必須堵塞。(未寫代碼測試)
2、假設是分布式的系統,使用synchronized無效了。由於synchronized最多僅僅能鎖住當前JVM的線程。對於其他server的線程無能為力。
那么怎么處理呢?
查了些資料。網上說能夠用zookeeper+其他組件完畢分布式鎖或者樂觀鎖。
由於沒有詳細實踐過。僅僅是看了幾篇文章。沒有發言權,所以感興趣的朋友能夠自行搜索 java+分布式鎖
完整測試demo源代碼:http://download.csdn.net/download/zl544434558/9495663