Java concurrent synchronized 關(guān)鍵字解析
synchronized是Java中的關(guān)鍵字绞呈,是一種同步鎖沪铭。它修飾的對(duì)象有以下幾種:
- 代碼塊
- 修飾方法
- 修飾靜態(tài)的方法
- 修飾類
修飾代碼塊DEMO
public class Account {
public void synchronizedMethod() throws InterruptedException {
synchronized (this) {
Thread.sleep(1000);
//todo
}
}
public void unSynchronizedMethod() {
//todo
System.err.println("I am not a sync thread,my thread name is " + Thread.currentThread().getName());
}
}
修飾代碼塊時(shí)旦装,被修飾的部分在同一時(shí)間點(diǎn)只能有一個(gè)線程A進(jìn)入泥栖,也就是說一個(gè)線程A已經(jīng)進(jìn)入Account一個(gè)實(shí)例 類的方法 synchronizedMethod幸斥,那么如果有其他的一個(gè)線程B此時(shí)想要訪問 同一個(gè) Account實(shí)例的 synchronizedMethod方法峭拘,必須等待已經(jīng)完成的線程A執(zhí)行完里邊同步的代碼塊俊庇。線程B才能進(jìn)入同步的代碼塊狮暑;但是如果線程B訪問的是 unSynchronizedMethod,那么則不需要等待辉饱。
注意 一定是同個(gè)Account實(shí)例搬男,如果是不同的實(shí)例,則沒有等待彭沼。
修飾方法DEMO
public class Account {
public synchronized void synchronizedMethod() throws InterruptedException {
//Thread.sleep(1000);
//todo
}
public void unSynchronizedMethod() {
//todo
System.err.println("I am not a sync thread,my thread name is " + Thread.currentThread().getName());
}
}
修飾方法和修飾代碼塊是一樣的缔逛,只不過兩個(gè)的同步的作用域是不同的,修飾方法作用域是整個(gè)方法姓惑,如果修飾的是代碼塊褐奴,則只是對(duì)代碼塊里邊的代碼進(jìn)行同步。
修飾靜態(tài)方法
/**
* Created by Jeffy on 17/5/20.
*/
public class Account {
public static synchronized void synchronizedMethod() throws InterruptedException {
System.err.println(Thread.currentThread().getName() + " is visiting this method");
Thread.sleep(5000);
//todo
}
public void unSynchronizedMethod() {
//todo
System.err.println("I am not a sync thread,my thread name is " + Thread.currentThread().getName());
}
}
測(cè)試類
/**
* Created by Jeffy on 17/5/20.
*/
public class SynchronizedMain {
public static void main(String[] args) throws InterruptedException {
new Thread(new Thread1(new Account()),"thread1").start();
new Thread(new Thread2(new Account()),"thread2").start();
}
static class Thread1 implements Runnable{
private Account account;
public Thread1(Account account) {
this.account = account;
}
@Override
public void run() {
try {
account.synchronizedMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class Thread2 implements Runnable{
private Account account;
public Thread2(Account account) {
this.account = account;
}
@Override
public void run() {
try {
account.synchronizedMethod();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
輸出
thread1 is visiting this method
thread2 is visiting this method
結(jié)果解釋于毙,你會(huì)發(fā)現(xiàn) thread1 is visiting this method 打印完之后大概用了5秒鐘之后 thread2 is visiting this method 才打印出來敦冬,說明synchronized修飾的靜態(tài)方法,同步的是這個(gè)Account的所有對(duì)象唯沮。而并非某一對(duì)象脖旱。
修飾類
public class Account {
public void synchronizedMethod() throws InterruptedException {
synchronized (this.getClass()) {
System.err.println(Thread.currentThread().getName() + " is visiting this method");
Thread.sleep(5000);
//todo
}
}
public void unSynchronizedMethod() {
//todo
System.err.println("I am not a sync thread,my thread name is " + Thread.currentThread().getName());
}
}
修飾的效果和修飾靜態(tài)的方法是一樣的,同步的是這個(gè)類的所有對(duì)象烂翰,并非某一個(gè)具體的實(shí)例夯缺。
synchronized關(guān)鍵字注意事項(xiàng)
- 雖然可以使用synchronized來定義方法,但synchronized并不屬于方法定義的一部分甘耿,因此踊兜,synchronized關(guān)鍵字不能被繼承。如果在父類中的某個(gè)方法使用了synchronized關(guān)鍵字佳恬,而在子類中覆蓋了這個(gè)方法捏境,在子類中的這個(gè)方法默認(rèn)情況下并不是同步的,而必須顯式地在子類的這個(gè)方法中加上synchronized關(guān)鍵字才可以毁葱。當(dāng)然垫言,還可以在子類方法中調(diào)用父類中相應(yīng)的方法,這樣雖然子類中的方法不是同步的倾剿,但子類調(diào)用了父類的同步方法筷频,因此,子類的方法也就相當(dāng)于同步了前痘。這兩種方式的例子代碼如下:
在子類方法中加上synchronized關(guān)鍵字 - 在定義接口方法時(shí)不能使用synchronized關(guān)鍵字凛捏。
- 構(gòu)造方法不能使用synchronized關(guān)鍵字,但可以使用synchronized代碼塊來進(jìn)行同步芹缔。
- 實(shí)現(xiàn)同步是要很大的系統(tǒng)開銷作為代價(jià)的坯癣,甚至可能造成死鎖,所以盡量避免無(wú)謂的同步控制