多线程不同步现象及解决

文章通过火车售票的例子介绍了Java中多线程并发时可能出现的问题,如线程安全问题,导致售票混乱。通过分析Service类的sale方法,解释了由于线程切换导致的票数更新不一致。解决方案是使用`synchronized`关键字确保方法的原子性,保证线程同步,从而避免数据冲突。
摘要由CSDN通过智能技术生成

在大致知道多线程的概念后,我们引入火车售票口售票的例子来学习线程的使用。

如何在java中实现并发式地卖票?

就像生活中那样,几个窗口卖同一堆票,互不干扰

我们先写出票类

public class Tickets {
    private int num=0;

    public Tickets() {
    }

    public Tickets(int num) {
        this.num = num;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }
}

再建立service类写入卖票的操作

public class Service {
    public void sale(Tickets t){
        int num=t.getNum();
        if(num>0){
            System.out.println("窗口在卖第"+num+"张票,剩下"+--num+"张票");
        }
        t.setNum(num);
    }
}

接下来新建windows类,作为售票的窗口,也是我们程序的主类

public class Windows {
    public static void main(String[] args) {
        Tickets t=new Tickets(100);
        Service s=new Service();
        new Thread(()->{
            while (t.getNum()>0){
                s.sale(t);
            }
        },"窗口1").start();
        new Thread(()->{
            while (t.getNum()>0){
                s.sale(t);
            }
        },"窗口2").start();
    }
}

窗口1,窗口2两个线程,重写了run方法,再调用start(),开辟了两块独立的栈内存。

就这样,我们简单还原了生活中卖票的情形,但运行结果却不尽人意。

窗口2在卖第46张票,剩下45张票
窗口1在卖第47张票,剩下46张票
窗口2在卖第45张票,剩下44张票
窗口1在卖第46张票,剩下45张票
窗口2在卖第44张票,剩下43张票
窗口1在卖第45张票,剩下44张票
窗口2在卖第43张票,剩下42张票

简单来说就是会出现卖的乱七八糟的情况
为什么会这样,对着service类的代码对那上面那个例子进行解读

public class Service {
    public void sale(Tickets t,String w){
        int num=t.getNum();
        if(num>0){
            System.out.println(w+"在卖第"+num+"张票,剩下"+--num+"张票");
        }
        t.setNum(num);
    }
}

首先每一个时间点只能执行两个窗口中的其中一个,他们是并发的,不能在内存中同时进行。
但内存对于线程的执行却并非是执行完一个线程的全部代码,他可能没被执行完就让别的线程从内存中挤出去了。

屏幕上显示

窗口2在卖第46张票,剩下45张票

说明窗口2已经执行完打印语句,但是否执行这个

 t.setNum(num);

不知道

_______________________________________________________

窗口1在卖第47张票,剩下46张票

说明窗口1此时在内存里看到的票数是47,但也不知道是否设置票数
_______________________________________________________

窗口2在卖第45张票,剩下44张票

这句就说明窗口2已经设置了票数,改为45
_______________________________________________________

窗口1在卖第46张票,剩下45张票

说明窗口1在上一次并未改票数,这时才执行t.setNum(num);将票数又改回了46
_______________________________________________________

所以就是这样,我们的程序出现了大问题

怎样解决,很简单,只要一个关键字 synchronized

public class Service {
    public synchronized void sale(Tickets t,String w){
        int num=t.getNum();
        if(num>0){
            System.out.println(w+"在卖第"+num+"张票,剩下"+--num+"张票");
        }
        t.setNum(num);
    }
}

再运行程序,就发现线程运行的井井有条,不会重票
synchronized就像一把锁,JAVA使用锁机制保证同步代码块或方法的“原子性”,即保持整体性,不可分割。

具体synchronized的作用原理就不再探讨了,本篇之探讨以上问题的解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值