Java多線程中synchronized(同步鎖),wait, notify,notifyAll的使用


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();
    }

}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM