一、同步问题的引出

  1、问题

  以卖火车票为例,如果现在要是想买大车票的话可以去火车站买或者去各个售票点,但是不管有多少个地方可以买火车票。最终一趟列车的车票数量是固定的, 如果把各个售票点理解为各个线程的话,则所有线程应该共同拥有同一份的票数。

  代码实现如下:

class BuyTicketThread implements Runnable{
    // 假设一共有5张票
    private int ticket = 5 ;    
    public void run(){
        //有这些人进行抢票
        for(int i=0;i<100;i++){
            //判断是否有票
            if(ticket>0){    // 还有票
                try{
                    Thread.sleep(300) ;    // 加入延迟
                }catch(InterruptedException e){
                    e.printStackTrace() ;
                }
                ticket--;
                //输出目前的票数
                System.out.println("得到一张票,现在票数:ticket = " + ticket );
            }
        }
    }
}
public class BuyTicket {
    public static void main(String[] args) {
        // 定义线程对象
        BuyTicketThread mt = new BuyTicketThread() ;    
        // 定义Thread对象代表不同的售票点
        Thread t1 = new Thread(mt) ;    
        Thread t2 = new Thread(mt) ;    
        Thread t3 = new Thread(mt) ;    
        t1.start() ;
        t2.start() ;
        t3.start() ;
    }
}

  输出结果每次运行都不一样,此处选取一种结果如下。

得到一张票,现在票数:ticket = 3
得到一张票,现在票数:ticket = 2
得到一张票,现在票数:ticket = 3
得到一张票,现在票数:ticket = 1
得到一张票,现在票数:ticket = -1
得到一张票,现在票数:ticket = 0

  此时,我们将发现结果完全不符合实际情况,数据出现混乱。这是因为多个线程访问同一个共享变量并对其进行修改,发生数据争用。  

  如果想解决这样的问题,就必须使用同步,所谓的同步就是指多个操作在同一时间段内只有一个线程运行,其他线程要等待此线程完成之后才可以继续执行。

  2、解决问题——使用同步代码块

   在代码块上加上“” 关键字的话,则此代码块就被称为同步代码块。

   同步代码块格式:

synchronized(同步对象){

  同步的时候,必须指明同步的对象,一般情况下会将当前对象作为同步对象,使用this表示。

  代码如下:

class BuyTicketThread implements Runnable{
    // 假设一共有5张票
    private int ticket = 5 ;    
    public void run(){
        //有这些人进行抢票
        for(int i=0;i<100;i++){
            //判断是否有票
            synchronized (this) {// 要对当前对象进行同步
                if(ticket>0){    // 还有票
                    try{
                        Thread.sleep(300) ;    // 加入延迟
                    }catch(InterruptedException e){
                        e.printStackTrace() ;
                    }
                    ticket--;
                    //输出目前的票数
                    System.out.println("得到一张票,现在票数:ticket = " + ticket );
                }
            }
        }
    }
}
public class BuyTicket {
    public static void main(String[] args) {
        // 定义线程对象
        BuyTicketThread mt = new BuyTicketThread() ;    
        // 定义Thread对象代表不同的售票点
        Thread t1 = new Thread(mt) ;    
        Thread t2 = new Thread(mt) ;    
        Thread t3 = new Thread(mt) ;    
        t1.start() ;
        t2.start() ;
        t3.start() ;
    }
}
得到一张票,现在票数:ticket = 4
得到一张票,现在票数:ticket = 3
得到一张票,现在票数:ticket = 2
得到一张票,现在票数:ticket = 1
得到一张票,现在票数:ticket = 0
输出结果

相关文章:

  • 2021-11-17
  • 2021-11-27
  • 2021-06-18
  • 2021-04-28
  • 2021-11-02
  • 2022-12-23
  • 2022-12-23
  • 2021-09-15
猜你喜欢
  • 2021-04-10
  • 2021-05-30
  • 2021-10-19
  • 2022-12-23
  • 2021-06-17
  • 2021-08-11
相关资源
相似解决方案