> 文档中心 > 同步方法解决数据安全问题(案例:卖票)

同步方法解决数据安全问题(案例:卖票)

同步方法解决数据安全问题

  • 一 案例:卖票
    • 1 卖票出现的问题:
    • 2 问题出现的原因:
  • 二 卖票案例的数据安全问题的解决:
    • 1. 为什么出现问题?
    • 2. 如何解决数据安全问题呢?
    • 3. 怎么实现?
    • 3. 利用同步代码块实现:
    • 5. 同步的好处和弊端?
  • 三 用代码写同步代码块
  • 四 "同步代码锁"的使用
    • 1 什么是同步方法锁
    • 2 利用代码分析"动态同步方法锁"
      • "SellTiket类"注意事项:
    • 3 利用代码分析"静态同步方法锁"
      • "SellTiket类"注意事项:

一 案例:卖票

  1. 需求:某电影院目前正在上映国产大片,共有100张票,而他有3个窗口卖票,请设计一个程序模拟该电影卖票
  2. 思路:
  • (1). 定义一个SellTicket类实现Runnable接口,里面定义一个成员变量:private int tickets=100;
  • (2). 在SellTicket类中重写run()方法实现卖票,代码步骤如下:
    判断票数大于0,就卖票,并告知是哪个窗口卖的卖了票之后,总票数减1,票没有了,也可能有人来问,所以这里用死循环让卖票动作一直执行
  1. 步骤:定义一个测试类SellTicketDemo,里面有main方法,代码步骤如下:
  • 创建SellTicket类的对象
  • 创建3个Thread类的对象,把SellTicket对象作为构造方法的参数,并给对应的窗口名称
  • 启动线程

1 卖票出现的问题:

  • 相同的票出现了多次
  • 出现了负数的票

2 问题出现的原因:

线程的随机性导致的

二 卖票案例的数据安全问题的解决:

1. 为什么出现问题?

这也是我们判断多线程程序是否有会有数据安全问题的标准

  • 是否是多线程环境
    本代码为主:
    吴含

  • 是否有共享数据
    本代码为主:
    吴含

  • 是否有多条语句操作共享数据

2. 如何解决数据安全问题呢?

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

3. 怎么实现?

  • 把多条语句操作共享数据的代码锁起来,让任意时刻只能有一个线程执行即可
  • Java提供了同步代码块的方式解决

3. 利用同步代码块实现:

锁多条语句操作共享数据,可以使用同步代码块实现,格式:

    synchronize(任意对象){多条语句操作共享数据的代码}

synchronize(任意对象):就相当于给代码加锁了,任意对象都可以看成一把锁

5. 同步的好处和弊端?

好处:解决了多线程的数据安全问题

弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

三 用代码写同步代码块

  • SellTicket
package Demo;public class SellTicket implements Runnable {    private int tickets = 100;    private Object obj=new Object();    @Override    public void run() { while (true) {     //tickets=100;     //t1,t2,t3     //假设t1抢到了CPU的执行权     //假设t2抢到了CPU的执行权,但是发现被obj锁上了,所以只能等待,即使t1休息也只能等     synchronized (obj) {  //t1进来后,就会把这段代码给锁起来  if (tickets > 0) {      try {   Thread.sleep(100);   //t1就要休息100毫秒      } catch (InterruptedException e) {   e.printStackTrace();      }      //t1休息好之后,窗口1正在出售第100张票      System.out.println("在" + Thread.currentThread().getName() + "号卖的票第" + tickets + "票");      tickets--;//tickets=99;  }     }     //t1出来了,这段代码锁就被释放了     //然后就是t2或者t3开始抢,抢到后和t1一样的执行过程 }    }}

图文解释:
吴含

  • SellTicketDemo
package Demo;public class SellTicketDemo {    public static void main(String[] args) { Runnable st = new SellTicket(); Thread tr = new Thread(st,"窗口1"); Thread tr2 = new Thread(st,"窗口2"); Thread tr3 = new Thread(st,"窗口3"); tr.start(); tr2.start(); tr3.start();    }}

四 "同步代码锁"的使用

1 什么是同步方法锁

就是把synchronized关键字加到方法上

  • 格式:
修饰符synchronized返回值类型 方法名(方法参数){    }
  • 同步方法锁的对象是什么:
    this

2 利用代码分析"动态同步方法锁"

SellTiket类
动态同步方法所的对象是"this"关键字

package Demo;public class SellTicket implements Runnable {    private int tickets = 100;//    private Object obj = new Object();    private int x = 0;    @Override    public void run() { while (true) {     if (x % 2 == 0) {//  synchronized (obj) {  synchronized (this) {      if (tickets > 0) {   try {Thread.sleep(100);   } catch (InterruptedException e) {e.printStackTrace();   }   System.out.println("在" + Thread.currentThread().getName() + "号卖的票第" + tickets + "票");   tickets--;      }  }     }else{  sellTicket();     }     x++; }    }    private synchronized void sellTicket() {     if (tickets > 0) {  try {      Thread.sleep(100);  } catch (InterruptedException e) {      e.printStackTrace();  }  System.out.println("在" + Thread.currentThread().getName() + "号卖的票第" + tickets + "票");  tickets--;     } }    }

"SellTiket类"注意事项:

吴含

SellTiketDemo

package Demo;public class SellTicketDemo {    public static void main(String[] args) { Runnable st = new SellTicket(); Thread tr = new Thread(st,"窗口1"); Thread tr2 = new Thread(st,"窗口2"); Thread tr3 = new Thread(st,"窗口3"); tr.start(); tr2.start(); tr3.start();    }}

3 利用代码分析"静态同步方法锁"

  • 就是把synchronized关键字加到静态方法上
  • 格式:
修饰符 static synchronized返回值类型 方法名(方法参数){    }
  • 同步静态方法的锁的对象是什么呢?
    类名.class
    SellTiket
    静态同步方法所的对象是"该类名.class"关键字
package Demo;public class SellTicket implements Runnable {    private  static int tickets = 100;//    private Object obj = new Object();    private int x = 0;    @Override    public void run() { while (true) {     if (x % 2 == 0) {//  synchronized (obj) {  synchronized (SellTicket.class) {      if (tickets > 0) {   try {Thread.sleep(100);   } catch (InterruptedException e) {e.printStackTrace();   }   System.out.println("在" + Thread.currentThread().getName() + "号卖的票第" + tickets + "票");   tickets--;      }  }     }else{  sellTicket();     }     x++; }    }    private static synchronized void sellTicket() {     if (tickets > 0) {  try {      Thread.sleep(100);  } catch (InterruptedException e) {      e.printStackTrace();  }  System.out.println("在" + Thread.currentThread().getName() + "号卖的票第" + tickets + "票");  tickets--;     } }    }

"SellTiket类"注意事项:

吴含

SellTiketDemo

package Demo;public class SellTicketDemo {    public static void main(String[] args) { Runnable st = new SellTicket(); Thread tr = new Thread(st,"窗口1"); Thread tr2 = new Thread(st,"窗口2"); Thread tr3 = new Thread(st,"窗口3"); tr.start(); tr2.start(); tr3.start();    }}