synchronized 鎖機制簡單的用法,高效的執行效率使成為解決線程安全的首選。 下面總結其特性以及使用技巧,加深對其理解。
特性:
1. Java語言的關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。
? ? ? 2. 當一個線程同時訪問object的一個synchronized(this)同步代碼塊時,其它線程仍然可以訪問非修飾的方法或代碼塊。
? ? ? 3. 當多個線程同時訪問object的synchronized(this)同步代碼塊時,會存在互斥訪問,其它線程會阻塞直到獲取鎖。
? ? ? 4. 當線程訪問object的synchronized(this)同步代碼塊時,同一個線程可以多次獲取鎖,當然也不需要釋放多次。獲取和釋放必須相同。
? ? ? 5. 所有的對象都可以獲取鎖,也可以釋放鎖。
? ? ? 6. 所有的類也可以獲取鎖和釋放鎖,因此靜態方法也可以加鎖。而特性同上。
猜想:
? ? ?在jvm中對每個對象都有一個記錄鎖的狀態,當同一個線程訪問鎖時候就會累加,其它線程訪問要等到狀態變為未鎖狀態,當讓相同線程釋放鎖會累減。
?質疑:
? ? 那么對于類鎖來說,應該是所有對象都可以獲取鎖,那么鎖是全局的對所有對象都有效?
public class SynchronizedMtdTest {public static void main(String[] args) {new Thread(new Runnable() {@Overridepublic void run() {SynchronizedMtdTest.appendStr();}}).start();new Thread(new Runnable() {@Overridepublic void run() {SynchronizedMtdTest.printStr();}}).start();new Thread(new Runnable() {@Overridepublic void run() {SynchronizedMtdTest synchronizedMtdTest = new SynchronizedMtdTest();synchronizedMtdTest.appendStr();}}).start();new Thread(new Runnable() {@Overridepublic void run() {SynchronizedMtdTest synchronizedMtdTest = new SynchronizedMtdTest();synchronizedMtdTest.printStr();}}).start();new Thread(new Runnable() {@Overridepublic void run() {SynchronizedMtdTest synchronizedMtdTest = new SynchronizedMtdTest();synchronizedMtdTest.append();}}).start();}public synchronized static void appendStr() {System.out.println("pid=" + Thread.currentThread().getId() + "------appendStr------");try {Thread.sleep(1000);System.out.println("pid=" + Thread.currentThread().getId() + "------appendStr1000------");} catch (InterruptedException e) {e.printStackTrace();}}public static void append() {System.out.println("pid=" + Thread.currentThread().getId() + "------append------");try {Thread.sleep(3000);System.out.println("pid=" + Thread.currentThread().getId() + "------append3000------");} catch (InterruptedException e) {e.printStackTrace();}}public synchronized static void printStr() {System.out.println("pid=" + Thread.currentThread().getId() + "------printStr------");try {Thread.sleep(6000);System.out.println("pid=" + Thread.currentThread().getId() + "------printStr6000------");} catch (InterruptedException e) {e.printStackTrace();}}}
結果:
pid=10------appendStr------
pid=14------append------
pid=10------appendStr1000------
pid=13------printStr------
pid=14------append3000------
pid=13------printStr6000------
pid=12------appendStr------
pid=12------appendStr1000------
pid=11------printStr------
pid=11------printStr6000------
?分析結果可以看出對于靜態方法加鎖,所有的線程調用方法,不管怎樣都會互斥,而為加鎖不會互斥。
因此:
? ? 對于類鎖來說應該在持久代也就是方法區有對具體類也有加鎖機制,而且原理同對象鎖。
那么:
? ? 可見,上面可以做如下修改達到相同效果。
public static void appendStr() {synchronized (SynchronizedMtdTest.class) {System.out.println("pid=" + Thread.currentThread().getId() + "------appendStr------");try {Thread.sleep(1000);System.out.println("pid=" + Thread.currentThread().getId() + "------appendStr1000------");} catch (InterruptedException e) {e.printStackTrace();}}}public static void printStr() {synchronized (SynchronizedMtdTest.class) {System.out.println("pid=" + Thread.currentThread().getId() + "------printStr------");try {Thread.sleep(6000);System.out.println("pid=" + Thread.currentThread().getId() + "------printStr6000------");} catch (InterruptedException e) {e.printStackTrace();}}}
?結果:
pid=10------appendStr------ pid=10------appendStr1000------ pid=13------printStr------ pid=13------printStr6000------ pid=12------appendStr------ pid=12------appendStr1000------ pid=11------printStr------ pid=11------printStr6000------
?