多線程共享同一資源時,在某一時間點上會出現多個線程同時訪問資源的情況。雖然編譯沒有問題,但是實際用起來卻很有可能造成困擾。比如車站賣票,把同一個號的兩張票賣給兩個人,特別是賣火車票的時候,恐怕這兩位拿同一號的乘客就會鬧矛盾了。比如下面的這個小例子:

代碼:

class MyThread4 implements Runnable{
    private int ticket = 8;//定義8張票
    public  void run(){
        for(int i=0;i<100;i++){
                if(this.ticket>0){
                    try{
                        Thread.sleep(100);
                    }catch(Exception e){}
                    System.out.println(Thread.currentThread().getName()+"號窗口"+

                     "==>On sael#######"+(ticket--));
                }
        }
    }
}

public class Tongbukuai {
    public static void main(String [] args){
        MyThread4 mt = new MyThread4();//共享同一資源
        Thread t1 = new Thread(mt);//
        Thread t2 = new Thread(mt);//三個線程代表三個售票窗口
        Thread t3 = new Thread(mt);//
        t1.start();
        t2.start();
        t3.start();
    }

}

運行結果:

image

      這怎么可以?2號和1號窗口賣出了兩張8號票,而且賣出的票的總數是不正常的。這是因為多個線程同時進入取票的循環,而程序還沒來得及把票數減一;后面的0號和-1號票的出現是因為當ticket 數為1的時候0號、1號和2號三個線程進入循環里,0號取得了1號票,此時應該停止買票了,但是1號、2號線程還在循環里,所以就依次取出了0號和-1號票。

      這種情況的處理辦法就是為資源加上一把“鎖”。每次只允許一個線程進入,當前的線程結束操作后才允許下一個線程進入。實現加同步鎖的操作有兩種方法:1、同步塊  2、同步方法。兩種方法都要用到synchronized關鍵字。

      代碼及運行結果如下:

同步塊:

class MyThread4 implements Runnable{
    private int ticket = 8;//定義8張票
    public  void run(){
        for(int i=0;i<8;i++){


            synchronized(this){
                if(this.ticket>0){
                    try{
                        Thread.sleep(100);
                    }catch(Exception e){}
                    System.out.println(Thread.currentThread().getName()+"號窗口"+

                     "==>On sael#######"+(ticket--));
                }
            }
        }
    }
}

public class Tongbukuai {
    public static void main(String [] args){
        MyThread4 mt = new MyThread4();//共享同一資源
        Thread t1 = new Thread(mt);//
        Thread t2 = new Thread(mt);//三個線程代表三個售票窗口
        Thread t3 = new Thread(mt);//
        t1.start();
        t2.start();
        t3.start();
    }

}

運行結果:

image

同步方法:

class MyThread4 implements Runnable{
    private int ticket = 8;//定義8張票
    public void run(){
        for(int i=0;i<8;i++){
            try{
                Thread.sleep(100);
            }catch(Exception e){}
            this.sale();
        }
    }
     public synchronized void sale(){
         {
                if(ticket>0)
                {
                    System.out.println(Thread.currentThread().getName()+"號窗口"+this.ticket--+"號票");
                }
        }
    }
}

public class Tongbukuai {
    public static void main(String [] args){
        MyThread4 mt = new MyThread4();//共享同一資源
        Thread t1 = new Thread(mt);//
        Thread t2 = new Thread(mt);//三個線程代表三個售票窗口
        Thread t3 = new Thread(mt);//
        t1.start();
        t2.start();
        t3.start();
    }

}

運行結果:

image

注意synchronized的位置,不要放錯位置哦!

我的這個就放錯了= =!!

class MyThread4 implements Runnable{
    private int ticket = 8;//定義8張票
    public  void run(){
        synchronized(this){   //一個窗口全部賣完
        for(int i=0;i<8;i++){
                if(this.ticket>0){
                    try{
                        Thread.sleep(100);
                    }catch(Exception e){}
                    System.out.println(Thread.currentThread().getName()+"號窗口"+"==>On sael#######"+(ticket--));
                }
        }
        }
    }
}

public class Tongbukuai {
    public static void main(String [] args){
        MyThread4 mt = new MyThread4();//共享同一資源
        Thread t1 = new Thread(mt);//
        Thread t2 = new Thread(mt);//三個線程代表三個售票窗口
        Thread t3 = new Thread(mt);//
        t1.start();
        t2.start();
        t3.start();
    }

}

看看結果:

image

     雖然沒賣重號的票,也沒多賣出0、-1號的,但是卻全都是一個窗口--0號窗口賣出去的。因為在ti也就是0號線程start的時候調用run()方法,然后0號就悲劇的被錯位的synchronized鎖在了里面,所以只能一個窗口全部賣完了。

     提醒一下大家,不要犯類似的錯誤。