java多线程重复卖票的问题

news/2024/5/17 20:21:44 标签: 多线程, synchronized, java
上代码:
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;
			}
			
		}

    }
}
运行结果:
java">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()的机会,出现重复卖票的可能性也会增加

修改后代码:

java">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;
				}				
			}
		}
    }
}
运行结果:
java">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





http://www.niftyadmin.cn/n/1735728.html

相关文章

创建的Dynamic web工程没有显示web.xml?

一直以来,自己创建的Dynamic web工程,没有显示web.xml,每一次需要粘贴复制,直到刚才,才找到了原因,满满的泪水,在这里分享下: 1、在Project Explorer栏下,右键 new--&g…

SecureCRT中文乱码解决方法

SecureCRT是一个商业终端连接工具。默认设置下,通过SecureCRT连接SSH服务器可能出现中文乱码的情况。这是由于SecureCRT字符编码与服务器的字符编码不一致造成的。 1.打开对话窗口,在工具栏中点开“选项”,选择“会话选项”。 2.在打开的“会…

BasicDataSource连接池使用

最近使用这类连接池发现有问题,当链接一个数据库如果数据库端异常或重启,就会出现提示链接数据库异常的信息。 所说报这样的错误,但是不影响程序的正常运行,所以一开始,忽略了Communications link failure,一直在the e…

12.log4j.properties例子:log4j.appender.file.Append与log4j.appender.file.Threshold

一、关于log4j.appender.file.Append的配置 测试类: import org.apache.log4j.Logger;public class HelloLog4J {// 构造记录器,形参是记录器所在的类,表示要在该类做日志 private static Logger logger Logger.getLogger(HelloLog4J.class); /** * param args…

使用Slf4j集成Log4j2构建项目日志系统的完美解决方案

本文转载于:http://www.cnblogs.com/hafiz/p/6160298.html 一、背景 最近因为公司项目性能需要,我们考虑把以前基于的log4j的日志系统重构成基于Slf4j和log4j2的日志系统,因为,使用slf4j可以很好的保证我们的日志系统具有良好的兼…

如何把maven项目转换成web项目

新接手的一个项目,是maven项目,却不是web项目,无法部署到tomcat上,在Jetty服务器上启动,平时运行倒也没啥问题,但是有时候升级改造的时候,与生产环境用tomcat启动不一样,这样就容易出…

log4j升级为log4j2(不需要改动代码)

公司的项目决定升级log4j,因为log4j2有一个自动删除日志的功能,这样可以减轻运维的一些工作,而且在多线程环境下,log4j2的异步日志系统比log4j和logback提高了十倍的性能(吞吐量和延迟率),官方原文如下&…

数据库主从分离

数据库的读写分离的好处? 1. 将读操作和写操作分离到不同的数据库上,避免主服务器出现性能瓶颈; 2. 主服务器进行写操作时,不影响查询应用服务器的查询性能,降低阻塞,提高并发; 3. 数据拥有多个…