1. 程式人生 > >java多個例項物件執行緒同步無效的原因以及解決方案

java多個例項物件執行緒同步無效的原因以及解決方案

【原因】:synchronized用法沒搞清楚

下面就直接舉例子了!

【情況1】:單例項物件多執行緒

public class Demo3 {
    Tlwindow twd1,twd2,twd3;    //定義三個視窗
    public static void main(String[] args){
        Demo3 demo3=new Demo3();
    }
    
    public Demo3(){
        twd1=new Tlwindow();
        Thread t1=new Thread(twd1);
        Thread t2=new Thread(twd1);
        Thread t3=new Thread(twd1);
        t1.start();
        t2.start();
        t3.start();
    }
}

//賣票視窗類
class Tlwindow implements Runnable{
    int num=2000;   //假設共有2000張票
    
    //重寫run
    //不斷地賣票
    public void run(){
        while(true){
            synchronized(this){
                try{
                    Thread.sleep(1000);
                }catch(Exception $e){
                    System.out.println("異常");
                }

                if(this.num>0){
                    System.out.println(Thread.currentThread().getName()+":當前正在賣"+num+"張票");
                    num--;
                }else{
                    break;
                }
            }
        }
    }
}


【情況2】:多例項物件多執行緒

public class Demo3 {
    Tlwindow twd1,twd2,twd3;    //定義三個視窗
    public static void main(String[] args){
        Demo3 demo3=new Demo3();
    }
    
    public Demo3(){
        twd1=new Tlwindow();
        twd2=new Tlwindow();
        twd3=new Tlwindow();
        Thread t1=new Thread(twd1);
        Thread t2=new Thread(twd2);
        Thread t3=new Thread(twd3);
        t1.start();
        t2.start();
        t3.start();
    }
}

//賣票視窗類
class Tlwindow implements Runnable{
    int num=2000;   //假設共有2000張票
    
    //重寫run
    //不斷地賣票
    public void run(){
        while(true){
            synchronized(Tlwindow.class){
                try{
                    Thread.sleep(1000);
                }catch(Exception $e){
                    System.out.println("異常");
                }

                if(this.num>0){
                    System.out.println(Thread.currentThread().getName()+":當前正在賣"+num+"張票");
                    num--;
                }else{
                    break;
                }
            }
        }
    }
}


【實現效果】:如下圖


【總結】:

synchronized(引數){  //注意這個“引數”,如果寫this範圍是類的一個例項物件,如果寫"類名.class"範圍是這個類的所有例項物件

    //你的程式碼

}

【更詳細的原理說明】:

  1. 某個物件例項內,synchronized (this類名){}可以防止多個執行緒同時訪問這個物件的synchronized方法(如果一個物件有多個synchronized方法,只要一個線 程訪問了其中的一個synchronized方法,其它執行緒不能同時訪問這個物件中任何一個synchronized方法)。這時,不同的物件例項的 synchronized方法是不相干擾的。也就是說,其它執行緒照樣可以同時訪問相同類的另一個物件例項中的synchronized方法;
  2. 某個類的範圍,synchronized (類名.class){}防止多個執行緒同時訪問這個類中的synchronized 裡面的程式碼。它可以對類的所有物件例項起作用。