synchronized(同步鎖)分為兩大類,n種使用場景,暫講5種場景;
第一大類:兩種使用場景:1.修飾該類的Class;2.修飾static方法,此時所有該類的對象只有一把同步鎖,多個對象訪問只有一個能拿到鎖,其他訪問該類,或者該static方法將被阻塞,只有拿到鎖的對象使用完,系統重新分配使用權;
/** * 在同類不同對象(new多次情況下)共用synchronized同步鎖 */ public class SynchronizedClass extends Thread{ /** * 1.synchronized(SynchronizedClass.class)修飾一個類,是給這個類加鎖,Ta的所有對象用的是同一把鎖(同步鎖) */ /*public void getCount(){ synchronized(SynchronizedClass.class){ for(int i = 0;i<5;i++){ System.out.println(Thread.currentThread().getName()+":i="+i); } } }*/ /** * 2.public synchronized static void getCount(){}修飾一個靜態方法,我們知道靜態方法是屬於類的而不屬於對象的, * 同樣的,synchronized修飾的靜態方法鎖定的是這個類的所有對象 */ public synchronized static void getCount(){ for(int i = 0;i<5;i++){ System.out.println(Thread.currentThread().getName()+":i="+i); } } @Override public void run() { // TODO Auto-generated method stub getCount(); } public static void main(String[] args) { /** * 測試方法:針對第一類:new兩個對象,但同步鎖依然有效 */ new SynchronizedClass().start(); new SynchronizedClass().start(); } }
第二大類:三種使用場景:1.修飾synchronized(this);2.修飾指定對象時(例如'銀行賬戶',或者生產者和消費者模式中的'儲存室');3.修飾一般方法,此三種場景都是針對同一對象而言,不可多次new,否則synchronized失去作用了;
package base.synchronize; import java.util.LinkedList; /** * 操作同一個對象時的同步鎖 synchronized */ public class CopyOfSynchronizedClass{ LinkedList<String> store =new LinkedList<String>(); /** * 3.public synchronized void getCount(){}修飾一個普通方法,只是對同一個對象的同步線程有影響,new SynchronizedClass()多一個同步鎖,不共用,豈不多鎖的效果 */ /*public synchronized void getCount(){ System.out.println("當前線程:"+Thread.currentThread().getName()); for(int i = 0;i<5;i++){ System.out.println(Thread.currentThread().getName()+":i="+i); } }*/ /** * 4.synchronized(this)修飾this同步代碼塊時,只是對同一個對象的同步線程有影響,其他試圖訪問該對象的線程將被阻塞。 * new SynchronizedClass()多一個同步鎖,不共用,豈不多鎖的效果 */ /*public void getCount(){ synchronized(this){ System.out.println("當前線程:"+Thread.currentThread().getName()); for(int i = 0;i<5;i++){ System.out.println(Thread.currentThread().getName()+":i="+i); } } }*/ /** * 5.synchronized(store)修飾store指定對象最好的場景:取錢,存錢;或者生產者模式,只是對同一個對象的同步線程有影響,其他試圖訪問該對象的線程將被阻塞。 * new SynchronizedClass()多一個同步鎖,不共用,豈不多鎖的效果 */ public void toTest(){ //為每個對象創建一個線程,一位是內部類,所有操作的外部CopyOfSynchronizedClass的store是公共的 new Thread(new Producer()).start(); new Thread(new Consumer()).start(); } //調用此方法,消費 public void getCount(){ synchronized(store){ while(true){ try{ while(store.size() == 0){ System.out.println("倉庫無貨!"); store.wait();//方法wait() 是無限期(一直)等待,直到其它線程調用notify或notifyAll方法喚醒當前的線程 } String str = store.removeLast(); System.out.println("消費貨品:"+str); Thread.sleep(200); store.notify();//notify()方法只喚醒一個等待(對象的)線程並使該線程開始執行。所以如果有多個線程等待一個對象,這個方法只會喚醒其中一個線程, //選擇哪個線程取決於操作系統對多線程管理的實現(因為此處只有'生產者'和'消費者',你懂得); //notifyAll()方法會喚醒所有等待(對象的)線程,哪一個線程將會第一個處理或訪問(加了synchronized修飾的場景)取決於操作系統的實現 }catch(InterruptedException e){ System.out.println("consumer is interrupted! msg="+e.getMessage()); } } } } int i=0; public void setCount(){ synchronized(store){ while(true){ try{ while(store.size() > 3){ System.out.println("倉庫貨物已滿!"); store.wait(); } String str = "貨物"+i; store.add(str); System.out.println("生產的貨物:"+str); Thread.sleep(200); store.notify(); i++; }catch(InterruptedException e){ System.out.println("Producer is interrupted! msg="+e.getMessage()); } } } } //生產者 class Producer implements Runnable{ @Override public void run() { setCount(); } } //消費者 class Consumer implements Runnable{ @Override public void run() { // TODO Auto-generated method stub getCount(); } } public static void main(String[] args) { /** * 第二大類:只new一個對象:synchronizedClass;所有動作都在這個對象中操作 */ CopyOfSynchronizedClass synchronizedClass = new CopyOfSynchronizedClass(); synchronizedClass.toTest(); } }