Java中线程的安全问题


假设我们现在要用代码实现这个场景:

售票处共有100张票,同时开设4个窗口同时售票,知道票售完为止

我们暂且将这种场景想象成线程的实现过程:四个线程同时售票,直到售完为止

使用Java API文档中线程使用的第一种方法,我们定义一个继承了Thread类的类Ticket,并重写run方法:

class Ticket extends Thread
{
private static  int num=100;
public void sale()
{
while(true)
{
if(num>0)
{
System.out.println(Thread.currentThread().getName()+"Sale:"+num--);
}
if(num==0)
{
//Thread.currentThread().stop();
break;
}
}
}

public void run()
{
sale();
}

在main函数中实例化四个Ticket对象,并同时开启这四个线程

public static void main(String[] args) 
{
Ticket t1=new Ticket();
Ticket t2=new Ticket();
Ticket t3=new Ticket();
Ticket t4=new Ticket();

t1.start();
t2.start();
t3.start();
t4.start();

}

运行代码,结果截图如下:


运行结果好像有些问题:为什么售票的顺序是错乱的呢?

问题的原因在于cmd也是一个程序,程序的执行是要依靠CPU的执行权,程序的运行是要靠CPU的不断切换执行权而运行的

在CPU在不同程序中不断的切换执行权的时候就会导致控制台结果输出的错乱。

好,排除了这个"异象",那程序的运行结果大概就是我们想要的结果了吧?从100递减到1,貌似没有什么问题。

现在我们在程序运行到run方法中的if(num>0)后让线程休息一段时间,将Ticket类改为以下代码:

class Ticket extends Thread
{
private static  int num=100;
public void sale()
{
while(true)
{
if(num>0)
{
try
{
Thread.sleep(20);
}
catch (InterruptedException e)
{
System.out.println("Error:"+e);
}
System.out.println(Thread.currentThread().getName()+"Sale:"+num--);
}
if(num==0)
{
//Thread.currentThread().stop();
break;
}
}
}
public void run()
{
sale();
}
}

运行结果,就会出现如图所示的灵异现象:


程序的结果居然出现了负值?!就像你买到的火车票是负数座位一样令人毛骨损人!见鬼了吗??

前面我们说过,程序的执行是在CPU不断切换执行权的情况下实现的,当某些线程在执行进入if(){}结果内,

让线程sleep()一段时间,这时就有可能有其它线程在这段时间内也进入了if(num>0){}内,因为进入{}的都满足了num>0

的条件,然后等线程休息结束后得到了执行权继续往下执行,就会把num值变成负数,这也就是线程灵异现象的产生原因。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值