线程安全问题的简单解决方案

线程安全

在多条线程访问的情况下,程序不能按照我们预期的结果进行,如下图所示:在这里插入图片描述

线程安全的解决方案

1.同步代码块

synchronized关键字,就是用来控制线程同步的,保证我们的线程在多线程环境下,不被多个线程同时执行,确保我们数据的完整性。
格式:synchronized(锁对象){}
简单点就是创建一个对象,然后把这个对象当成一个餐厅大妈,每个线程看成一个个人。当一个个人排队打饭的时候,只有等每个人打饭完后,才能轮到下一个,也就是强制排队。

 static class  Ticket implements Runnable{
        //票数
        private int count = 10;
        private Object o = new Object();
        @Override
        public void run() {
                while (true) {
                    synchronized (o) {
                        if (count > 0) {
                        //买票
                        System.out.println("正在准备卖票");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //出票
                        count--;
                        //出票成功
                        System.out.println(Thread.currentThread().getName()+"出票成功,余票:" + count);
                    }
                        else{
                            break;
                        }
                }
            }
        }
    }

2.同步方法

把要处理的活动封装成一个方法,然后用synchronized对方法进行修饰,然后把方法返回一个boolean型的数据。相对于第一种的同步代码块而言,不用再去创建对象,直接用synchronized修饰方法就可以进行排队打饭,只有一个线程结束了,下一个线程才能够进来。

 static class  Ticket implements Runnable{
        //票数
        private int count = 10;
        @Override
        public void run() {
            while (true) {
               boolean flag = sale();
               if (!flag){
                   break;
               }
            }
        }
        public synchronized boolean sale(){
                if (count > 0) {
                    //买票
                    System.out.println("正在准备卖票");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //出票
                    count--;
                    //出票成功
                    System.out.println(Thread.currentThread().getName()+"出票成功,余票:" + count);
                    return true;
                }
                else{
                    return false;
                }
        }

    }

3.Lock锁

Lock是一个接口,无法创建实例,所以在这边我们创建了它的子类ReentrantLock,然后继承了父类的Lock的方法lock(),用来获取锁。unlock()用来释放锁。使用的方法就是线程进入时,用lock()锁住,结束时用unlock()进行解锁。

    static class  Ticket implements Runnable{
        //票数
        private int count = 10;
        //显示锁Lock 子类 ReentrantLock
        Lock l = new ReentrantLock();
        @Override
        public void run() {
            while (true) {
                l.lock();
                if (count > 0){
                    //买票
                    System.out.println("正在准备卖票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //出票
                count--;
                //出票成功
                System.out.println("出票成功,余票:" + count);
            }else{
                    break;
                }
              l.unlock();
        }
        }
    }

欢迎评价

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值