再美不及姑娘你
又见西风上碧树

需求:某车站出售舟山至宁波的车票,共一百张,有三个窗口卖票,请设计一个程序模拟窗口卖票

分析:

1.定义一个SellTicket类实现Runnable接口,并重写run方法,并定义车票总张数

2.在run方法中判断票是否大于0;

是:卖票,并告知哪个窗口卖出的,卖票后总票数减一

否:提示没票了

3.定义一个测试类,创建SellTicket类对象,并作为参数创建三个Thread类对象,赋予线程名

4.启动线程

SellTicket类

public class SellTicket implements Runnable{
  //定义总张数
  private int tickets=100;
  @Override
  public void run() {
      while (true) {
          //判断车票是否大于0
          if (tickets > 0) {
              System.out.println(Thread.currentThread().getName() + "卖出第" + tickets + "张车票");
              tickets--;
          }

      }
  }
}

SellTicketDemo类

public class SellTicketDemo {
  public static void main(String[] args) {
      //创建SellTicket类对象
      SellTicket st=new SellTicket();
      //作为参数创建三个Thread类对象,赋予线程名
      Thread t=new Thread(st,"窗口一");
      Thread t1=new Thread(st,"窗口二");
      Thread t2=new Thread(st,"窗口三");
      //启动线程
      t.start();
      t1.start();
      t2.start();
  }
}

经过运行发现会出现两个问题:

1.三个线程卖出了相同号码的车票

2.卖出了负数的车票

导致两个问题出现的原因是线程的随机性导致的数据安全问题。

一、那么如何判断多线程程序是否有数据安全问题?

1.判断程序是否是多线程环境

2.判断程序是否有共享数据

3.判断程序是否有多条语句操作共享数据

二、如何解决多线程安全问题?

1.基本思想:让程序没有安全问题的环境

2.把多条语句操作共享数据的代码块锁起来,让任意时刻只能有一个线程执行

这里使用同步代码块的方式来解决

三、同步代码块

格式:

synchronized(任意对象){

多条语句操作共享数据的代码;

}

synchronized(任意对象):就相当于给代码加锁了,任意对象就可以看作是一把锁

修改后SellTicket类

import static java.lang.Thread.sleep;

public class SellTicket implements Runnable{
  //定义总张数
  private int tickets=100;
  //定义一把锁
  private Object obj=new Object();
  @Override
  public void run() {
      synchronized (obj){
      while (true) {
          //判断车票是否大于0
          if (tickets > 0) {
              System.out.println(Thread.currentThread().getName() + "卖出第" + tickets + "张车票");
              tickets--;
              //模仿出票
              try {
                  sleep(100);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      }

      }
  }
}

这样就解决了以上两个问题。

四、同步代码块的优缺点

1.优点:解决了多线程的数据安全问题

2.缺点:当线程很多时,因为每个线程都会去判断同步代码块中的锁,很耗费资源,会降低程序的运行效率

五、同步方法

1.同步方法就是把synchronized关键字加在方法上

格式:

修饰符synchronized 返回值类型 方法名(方法参数){}

public synchronized void sellTiket(){}

同步方法的锁对象是 this

synchronized (this)

2.同步静态方法就是把synchronized关键字加在静态方法上

格式:

修饰符 static synchronized 返回值类型 方法名(方法参数){}

public static synchronized void sellTiket(){}

同步方法的锁对象是类名.class

synchronized (SellTicket.class)

 

posted on 2022-04-14 20:42  再美不及姑娘你  阅读(255)  评论(0)    收藏  举报