多线程共享同一资源时,在某一时间点上会出现多个线程同时访问资源的情况。虽然编译没有问题,但是实际用起来却很有可能造成困扰。比如车站卖票,把同一个号的两张票卖给两个人,特别是卖火车票的时候,恐怕这两位拿同一号的乘客就会闹矛盾了。比如下面的这个小例子:

代码:

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锁在了里面,所以只能一个窗口全部卖完了。

     提醒一下大家,不要犯类似的错误。