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

一 案例:卖票

  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();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发热的嘤嘤怪(2003计科胜胜同学)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值