Thread线程二 多线程服务 卖票服务

卖票服务

引入问题:
有一百张票,分为三个从窗口

测试类

public static void main(String[] args) {
    RunnableImpl run=new RunnableImpl();
    Thread t0=new Thread(run);
    Thread t1=new Thread(run);
    Thread t2=new Thread(run);
    //调用start,开启多线程
    t0.start();
    t1.start();
    t2.start();
}

第一次代码:

只要有票就售出,三个窗口为三个线程,同时执行

public class RunnableImpl implements Runnable {
private int ticket=100;
@Override
public void run() {
    while (true)
    {
        if(ticket>0)
        {
            System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");
            ticket--;
            
        }
    }

}
}

效果:
Thread-2正在卖第100张票!
Thread-2正在卖第99张票!
Thread-2正在卖第98张票!
Thread-1正在卖第100张票!
Thread-1正在卖第96张票!
Thread-2正在卖第97张票!
Thread-2正在卖第94张票!
Thread-2正在卖第93张票!
Thread-0正在卖第100张票!
原因:线程争夺资源,同时进入cpu中,系统没有调休实现,所以出现票重复 卖出的情况。

改进算法:

卖票的时间每个改为10ms,意味着线程休眠10ms。使得资源得以缓冲
static void sleep(long millis)
使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。

public class RunnableImpl implements Runnable {
private int ticket=100;
@Override
public void run() {
    while (true)
    {
       try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(ticket>0)
        {
            System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");
            ticket--;

        }
    }

}
}

效果:
Thread-0正在卖第100张票!
Thread-1正在卖第100张票!
Thread-2正在卖第100张票!
Thread-0正在卖第97张票!
Thread-1正在卖第97张票!
Thread-2正在卖第95张票!
原因:还是因为争夺cpu,同时进入,改进并没有找到根本原因!
在这里插入图片描述

使用synchronized(锁对象)同步代码块

synchronized(锁对象)
{可能会出现线程安全问题的代码(访问了共享数据的代码)}
注意:

  • 1.通过代码块中的锁对象,可以使用任意的对象

  • 2.但是必须保证多个线程使用的锁对象是同一个

  • 3.锁对象作用:

  • 把同步代码块锁住,只让一个线程在同步代码块中执行

      public class RunnableImpl implements Runnable {
      private  int ticket=100;
      //创建一个锁对象
    Object obj=new Object();
    @Override
     public void run() {
      while (true)
      {//同步代码块
          synchronized (obj)//也可以synchronized(this)
      {
    
          try {
              Thread.sleep(10);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
          if(ticket>0)
          {
              System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");
              ticket--;
          }
      }
      }
       }
      }
    

    效果:
    Thread-0正在卖第100张票!
    Thread-0正在卖第99张票!
    Thread-0正在卖第98张票!
    Thread-0正在卖第97张票!
    Thread-0正在卖第96张票!
    Thread-0正在卖第95张票!
    Thread-0正在卖第94张票!
    Thread-0正在卖第93张票!
    原理:
    在这里插入图片描述

使用同步方法

锁对象是this
使用步骤:
1.把访问了共享数据代码抽取出来,放入到一个方法中
2.在方法上添加synchronized
代码:

public class RunnableImpl implements Runnable {
private int ticket=100;
//创建一个锁对象
@Override
public void run() {
    while (true)
    {//同步代码块
        payTicket();
    }

}
public synchronized void payTicket()
{
    if(ticket>0)
    {
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");
        ticket--;
    }
}
}

效果:
Thread-0正在卖第100张票!
Thread-0正在卖第99张票!
Thread-0正在卖第98张票!
Thread-0正在卖第97张票!
Thread-0正在卖第96张票!
Thread-0正在卖第95张票!
Thread-0正在卖第94张票!
Thread-0正在卖第93张票!
设置票为私有静态,则同步方法也是静态方法
静态的同步方法
锁对象是静态方法的锁对象是本类的class属性–>class文件对象(反射

代码:

public class RunnableImpl implements Runnable {
private static int ticket=100;

//创建一个锁对象
@Override
public void run() {
    while (true)
    {//同步代码块
        payTicket();
    }

}
/*使用静态方法解决同步问题*/
public static synchronized void payTicket()
{
    //去掉synchronized 关键字换上
    //synchronized(RunnableImpl.class){}
    if(ticket>0)
    {
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票!");
        ticket--;
    }
}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值