參考鏈接:
http://blog.csdn.net/luoweifu/article/details/46613015
http://blog.csdn.net/lan861698789/article/details/50425554
簡述
synchronized(this/obj){
//只要執行這段代碼塊的線程沒執行完,對於this/obj對象的同步區域就是不允許無鑰匙訪問,如this或obj中的printCpu()方法
}
public synchronized void printCpu() {//同步塊
}
理論
- 無論synchronized關鍵字加在方法上還是對象上,如果它作用的對象是非靜態的,則它取得的鎖是對象;如果synchronized作用的對象是一個靜態方法或一個類,則它取得的鎖是對類,該類所有的對象同一把鎖。
這可以理解爲對內存區域上鎖,static的就是所有對象的共享區,共享區上鎖,所有對象對這個區域的訪問都需要’鑰匙’,普通對象享有自己的內存區域。上鎖就隻影響到對這個對象的操作
- 每個對象只有一個鎖(lock)與之相關聯,誰拿到這個鎖誰就可以運行它所控制的那段代碼。
比如下面的Resource類,printCpu()方法是同步方法
public class Resource {
private int cpu;
public synchronized void printCpu() {
System.out.println(Thread.currentThread().getName()+":"+this.cpu++);
}
}
- 實現同步是要很大的系統開銷作爲代價的,甚至可能造成死鎖,所以儘量避免無謂的同步控制。但是必要的同步操作還是需要的,避免造成數據的錯亂。而且jdk也在對synchronized進行優化
總結
-
線程等待(阻塞):當兩個併發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以後才能執行該代碼塊。
-
非同步代碼塊可訪問:當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。
ps: 同步塊和非同步塊,就像一家商場裏鎖門的商店和沒鎖的商店,而不是說把商場鎖了,線程就分爲有鑰匙和沒鑰匙的人,沒鑰匙的人就只能去訪問沒鎖的商店
Tip:
當沒有明確的對象作爲鎖,只是想讓一段代碼同步時,可以創建一個特殊的對象來充當鎖:
class Test implements Runnable
{
private byte[] lock = new byte[0]; // 特殊的instance變量
public void method()
{
synchronized(lock) { //我理解爲對lock上鎖,且先運行到這裏的線程拿了唯一一把鑰匙
// todo 同步代碼塊
}
}
}
說明:零長度的byte數組對象創建起來將比任何對象都經濟――查看編譯後的字節碼: 生成零長度的byte[]對象只需3條操作碼,而Object lock = new Object()則需要7行操作碼。
synchronized關鍵字不能繼承:
class Parent {
public synchronized void method() { }
}
class Child extends Parent {
public synchronized void method() { }//方法還是需要使用關鍵字聲明,或者無效
}
死鎖demo:死鎖是怎樣形成的