今天要分享的內容是synchronized
這個地方也是,說起來知道同步的用法,但是並不是多麼的清楚,和上面的那篇mysql的子查詢一樣,看到代碼中很多這樣寫的。
就順便研究總結一下:
修飾對象有幾種(能出現在什麼地方)
- 修飾一個類,其作用的範圍是synchronized後面括號括起來的部分, 作用的對象是這個類的所有對象。
- 修飾一個方法,被修飾的方法稱爲同步方法,其作用的範圍是整個方法, 作用的對象是調用這個方法的對象;
- 修改一個靜態的方法,其作用的範圍是整個靜態方法, 作用的對象是這個類的所有對象;
- 修飾一個代碼塊,被修飾的代碼塊稱爲同步語句塊,其作用的範圍是大括號{}括起來的代碼, 作用的對象是調用這個代碼塊的對象;
2個鎖
上面的4種情況,核心也就是,2個鎖
- 對象鎖,修飾一個類的成員方法和代碼塊,就是這種情況,他強調的是創建對象,調用對象本身,比如,a對象和b對象完全不同
- 類鎖(其實沒有,類比概念,好理解),也就是修飾類,和靜態的方法,這兩種的同步是一樣的,他們強調的是類class這個對象的鎖,因此a對象和b對象擁有同樣的鎖,所以是相同的
廢話不多說,直接上例子吧
/**
* @author hankun
* @create 2017-07-05 19:52
*/
public class synchronizedTest {
/**
* 同步線程,修飾方法塊
*/
static class SyncMehtodBlock implements Runnable {
private static int count;
public SyncMehtodBlock() {
count = 0;
}
public void run() {
synchronized (this) {
System.out.println(Thread.currentThread().getName() + "開始..SyncMehtodBlock");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "結束..SyncMehtodBlock");
}
}
}
/**
* 同步線程,修飾方法
*/
static class SyncMehtod extends Thread {
private synchronizedTest syn;
public SyncMehtod(synchronizedTest synchronizedTest) {
this.syn = synchronizedTest;
}
public void run() {
syn.test();
}
}
public synchronized void test() {
System.out.println(Thread.currentThread().getName() + "開始..SyncMehtod");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "結束..SyncMehtod");
}
/**
* 同步線程,修飾靜態方法
*/
static class SyncStaticMehtod extends Thread {
public synchronized static void staticTest() {
System.out.println(Thread.currentThread().getName() + "開始..SyncStaticMehtod");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "結束..SyncStaticMehtod");
}
public void run() {
staticTest();
}
}
/**
* 同步線程,修飾類
*/
static class SyncClass extends Thread {
public void classTest() {
synchronized (synchronizedTest.class) {
System.out.println(Thread.currentThread().getName() + "開始..SyncClass");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "結束..SyncClass");
}
}
public void run() {
classTest();
}
}
public static void main(String[] args) {
//情況1,修飾方法塊
SyncMehtodBlock syncMehtodBlock = new SyncMehtodBlock();
Thread thread1 = new Thread(syncMehtodBlock, "syncMehtodBlock1");
Thread thread2 = new Thread(syncMehtodBlock, "syncMehtodBlock2");
thread1.start();
thread2.start();
//情況2,修飾方法
synchronizedTest syn = new synchronizedTest();
SyncMehtod syncMehtod3 = new SyncMehtod(syn);
SyncMehtod syncMehtod4 = new SyncMehtod(syn);
syncMehtod3.start();
syncMehtod4.start();
//情況3,修飾靜態方法
SyncStaticMehtod a = new SyncStaticMehtod();
SyncStaticMehtod b = new SyncStaticMehtod();
Thread thread5 = new Thread(a, "SyncStaticMehtod1");
Thread thread6 = new Thread(b, "SyncStaticMehtod2");
thread5.start();
thread6.start();
//情況4,修飾類
SyncClass c = new SyncClass();
SyncClass d = new SyncClass();
Thread thread7 = new Thread(c, "SyncClass1");
Thread thread8 = new Thread(d, "SyncClass2");
thread7.start();
thread8.start();
}
}
我寫了一個,模擬4種情況的例子,報每個類型都包含進去了
請注意觀察裏面的synchronized的關鍵位置,出現的情況,以及每個測試例子,是如何新建的,區分不同
所有的例子,都是具有同步的,因爲競爭,比如,a先開始,那麼a先結束,然後才能輪到b開始,b結束
好好,體會裏面的內容
總結
- 無論synchronized關鍵字加在方法上還是對象上,如果它作用的對象是非靜態的,則它取得的鎖是對象;如果synchronized作用的對象是一個靜態方法或一個類,則它取得的鎖是對類,該類所有的對象同一把鎖。
- 每個對象只有一個鎖(lock)與之相關聯,誰拿到這個鎖誰就可以運行它所控制的那段代碼。
- 實現同步是要很大的系統開銷作爲代價的,甚至可能造成死鎖,所以儘量避免無謂的同步控制。
我覺得別人說的,這三句話,已經說的很明白不過,我也就不加自己的體會了