java中cpu分给每个线程的时间片是随机的并且在java中好多都是多个线程共用一个资源,比如火车卖票,火车票是一定的,但卖火车票的窗口到处都有,每个窗口就相当于一个线程,这么多的线程共用所有的火车票这个资源。如果在一个时间点上,两个线程同时使用这个资源,那他们取出的火车票是一样的(座位号一样),这样就会给乘客造成麻烦。
比如下面的代码:
public class TicketSouce implements Runnable {
//票的总数
private int ticket=10;
public void run()
{
for(int i=1;i<50;i++)
{
if(ticket>0)
{
//休眠1s秒中,为了使效果更明显,否则可能出不了效果
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"号窗口卖出"+this.ticket--+"号票");
}
}
}
}
我们编写一个测试类测试一下,显示一下效果。
public class Test {
public static void main(String [] arg){
TicketSouce mt=new TicketSouce();
//基于火车票创建三个窗口
new Thread(mt,"a").start();
new Thread(mt,"b").start();
new Thread(mt,"c").start();
}
}
显示一下结果:
a号窗口卖出10号票
b号窗口卖出8号票
a号窗口卖出7号票
c号窗口卖出7号票
b号窗口卖出6号票
a号窗口卖出5号票
c号窗口卖出4号票
b号窗口卖出3号票
c号窗口卖出2号票
a号窗口卖出1号票
b号窗口卖出0号票
我们可以看到a号窗口和c号窗口都卖出了7号票,也就是7号票被卖出了两次,出现这种感觉情况的原因就是,在a号窗口卖出7号票还没有进行票号减一的时候,c号窗口正好再买7好票,导致7好票被卖出了两次。
这种情况就需要我们引入锁(synchronized)来控制这种情况的发生。
我们将上面的情况修改一下:
public class TicketSouce2 implements Runnable{//票的总数
private int ticket=10;
public void run()
{
for(int i=1;i<50;i++)
{
try {
//休眠1s秒中,为了使效果更明显,否则可能出不了效果
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.sale();
}
}
public synchronized void sale()
{
if(ticket>0)
{
System.out.println(Thread.currentThread().getName()+"号窗口卖出"+this.ticket--+"号票");
}
}
}
我们在用测试类测试一下就可以看到结果:
a号窗口卖出10号票
c号窗口卖出9号票
b号窗口卖出8号票
c号窗口卖出7号票
a号窗口卖出6号票
b号窗口卖出5号票
c号窗口卖出4号票
a号窗口卖出3号票
b号窗口卖出2号票
c号窗口卖出1号票