首页 > 代码库 > 线程同步

线程同步

      JAVA程序中有多个线程时,cpu分配给每个线程的时间片是在保证均衡的基础上随机分配的,如果这多个线程有部分相同的功能调用,那么在功能调用过程中可能会因为时间片的随机分配产生预想不到的结果。例如火车卖票的程序,火车票是一定的,但卖火车票的窗口到处都有,每个窗口就相当于一个线程,这么多的线程共用所有的火车票这个资源。如果在一个时间点上,两个线程同时使用这个资源,那他们取出的火车票可能是一样的(座位号一样),这样就会给乘客造成麻烦。

package com.dr.runnable2;
class TicketSouce implements Runnable{
         //票总数
         private int ticket=10;
         public void run()  {
               for(int i=1;i<50;i++) {
                    if(ticket>0){                                     
                            System.out.println(Thread.currentThread().getName()+"号窗口卖出"+this.ticket--+"号票");
                    }
               }
         }
}
public class Test {
      public static void main(String args[]) {
            TicketSouce mt=new TicketSouce();
            //基于火车票创建三个窗口
            new Thread(mt,"a").start();
            new Thread(mt,"b").start();
            new Thread(mt,"c").start();
      } 

可能的运行结果如下 (小概率)

 技术分享

技术分享

      出现相同的10号票是因为当a线程执行“ System.out.println(Thread.currentThread().getName()+"号窗口卖出"+this.ticket--+"号票")”时还没有对ticket进行自减1,时间片就被分配到b线程,结果b线程也取到了10号票。出现0和-1是因为b线程取出1号票还没有对ticket进行自减1,a和c线程就相继取得时间片利用ticket=1成功通过if(ticket>0)的判断句进入循环,然后再回到b将ticket减为0,结果先执行的a输出0,后执行的c输出-1。

      synchronized线程同步, 用于解决此类问题。同步方法synchronized void method(){}或同步语句synchronized(object){}放置在正确的位置均可实现。使用后当某线程进行功能调用时在没有得到结果之前不会返回,其他线程也无法调用,如果需要调用会暂时阻塞。将程序改为同步方法:

package com.dr.runnable2;
class TicketSouce implements Runnable{
       //票总数
       private int ticket=10;
       public void run()  {
             for(int i=1;i<50;i++) {
                   this.sale();
             }
       }
       public synchronized void  sale(){
             if(ticket>0){                                     

                   System.out.println(Thread.currentThread().getName()+"号窗口卖出"+this.ticket--+"号票");

             } 
       }
}
 public class Test {
             public static void main(String args[]) {
                     TicketSouce mt=new TicketSouce();
                      //基于火车票创建三个窗口
                      new Thread(mt,"a").start();
                      new Thread(mt,"b").start();
                      new Thread(mt,"c").start();
               } 
}  
或同步语句:
package com.dr.runnable2;
 class TicketSouce implements Runnable{
           //票总数
            private int ticket=10;
            public void run()  {
                     for(int i=1;i<50;i++) {
                            synchronized(this){   
                                     if(ticket>0){
                                               System.out.println(Thread.currentThread().getName()+"号窗口卖出"+this.ticket--+"号票");
                                     }
                             }
                       }
              }
}
 public class Test {
             public static void main(String args[]) {
                     TicketSouce mt=new TicketSouce();
                      //基于火车票创建三个窗口
                      new Thread(mt,"a").start();
                      new Thread(mt,"b").start();
                      new Thread(mt,"c").start();
               } 
}  
运行结果:
技术分享

 

线程同步