java多线程重复卖票的问题

上代码:
public class Test {
	public static void main(String[] args) {
        ThreadTicket ticket = new ThreadTicket();
        Thread t1 = new Thread(ticket); 
        Thread t2 = new Thread(ticket); 
        t1.start();
        t2.start();
    }
}

class ThreadTicket implements Runnable {
    int ticket = 10;
    @Override
    public void run() {
			
		while(true) {
			if(ticket>0) {
				try {
					Thread.currentThread();
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName()+"卖。。。"+ticket--);               
			} else {
				break;
			}
			
		}

    }
}
运行结果:
Thread-1卖。。。10
Thread-0卖。。。10
Thread-0卖。。。9
Thread-1卖。。。8
Thread-1卖。。。7
Thread-0卖。。。6
Thread-0卖。。。4
Thread-1卖。。。5
Thread-0卖。。。3
Thread-1卖。。。2
Thread-1卖。。。1
Thread-0卖。。。0

问题:偶尔会出现重复卖票的情况,显示这在开发中是不允许的

原因分析:java中的原子性操作,是指读和写是原子性的,比如 i=5,这就是一个原子性的操作。多线程执行的时候,只能在一个原子操作力,才会没有并发读或并发写的情况。

通常情况下,在java里面,i++或者i--不是线程安全的,这里面有三个独立的操作:获得变量当前的值,为该值+1或者-1,然后写回新的值。

在没有额外资源可以利用的情况下,只能使用加锁才能保证读-改-写这三个操作是原子性的,这就是为什么会出现一定数量重复卖票的情况

另外,sleep()中指定的时间是线程不会运行的最短时间,因此,sleep()方法不能保证该线程睡眠到期后就开始执行,所以,加上sleep()以后,就增加了并发操作ticket()的机会,出现重复卖票的可能性也会增加

修改后代码:

class ThreadTicket implements Runnable {
    int ticket = 10;
    @Override
    public void run() {
		synchronized (this) {			
			while(true) {
				if(ticket>0) {
					try {
						Thread.currentThread();
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"卖。。。"+ticket--);               
				} else {
					break;
				}				
			}
		}
    }
}
运行结果:
Thread-0卖。。。10
Thread-0卖。。。9
Thread-0卖。。。8
Thread-0卖。。。7
Thread-0卖。。。6
Thread-0卖。。。5
Thread-0卖。。。4
Thread-0卖。。。3
Thread-0卖。。。2
Thread-0卖。。。1




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值