java多线程_从售票模拟浅谈线程安全问题
初步编写售票程序
- 定义票数临界区,实现Ranable接口
class TicketCount implements Runnable{ private int tiketCount = 100 ; @Override public void run() { // TODO Auto-generated method stub while(tiketCount>0) sale() ; } public void sale(){ System.out.println(Thread.currentThread().getName()+"售出第"+(100 - tiketCount + 1)+"张票"); tiketCount-- ; } }
- 定义两个线程共享临界区同时进行售票操作(写操作)
TicketCount initTiketCount = new TicketCount() ; Thread SaleWindow1 = new Thread(initTiketCount,"售票窗口1") ; Thread SaleWindow2 = new Thread(initTiketCount,"售票窗口2") ; SaleWindow1.start(); SaleWindow2.start();
-
运行结果(节选)
售票窗口1售出第1张票 售票窗口2售出第1张票 售票窗口2售出第3张票 售票窗口2售出第4张票 售票窗口1售出第2张票 售票窗口2售出第5张票 售票窗口1售出第6张票 售票窗口2售出第7张票 售票窗口2售出第9张票 售票窗口1售出第8张票 售票窗口2售出第10张票 售票窗口1售出第11张票 售票窗口2售出第12张票 售票窗口1售出第13张票 售票窗口2售出第14张票 售票窗口1售出第15张票 售票窗口2售出第16张票 售票窗口1售出第17张票 售票窗口2售出第18张票 售票窗口1售出第19张票 售票窗口2售出第20张票
-
问题分析:由运行结果可以看出两个售票口同时卖出了第一张票,这从逻辑上是有问题的。这是由于程序并发带来的问题,在售卖第一张票时两个线程同时进入了售票的方法,对临界区进行了写操作,因此出现了同时卖出第一张票的情况。
线程安全问题
当多个线程对同一个临界区进行写操作时,会产生线程安全问题。 - 解决方法:考虑线程同步:synchronize,lock锁
改良代码
-
使用synchronize加对象锁,只有竞争到锁的线程才能进去临界区,否则等待。 建立一个对象当做锁
Object objLock = new Object() ;
- 用synchronize包裹需要进行控制的代码。
public void sale(){ try { Thread.sleep(30); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } synchronized(objLock){ if(tiketCount > 0){ System.out.println(Thread.currentThread().getName()+"售出第"+(100 - tiketCount + 1)+"张票"); tiketCount-- ; } } }
或者:
public synchronized void sale(){ try { Thread.sleep(30); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(tiketCount > 0){ System.out.println(Thread.currentThread().getName()+"售出第"+(100 - tiketCount + 1)+"张票"); tiketCount-- ;
-
运行结果(节选):
售票窗口2售出第1张票 售票窗口1售出第2张票 售票窗口1售出第3张票 售票窗口2售出第4张票 售票窗口1售出第5张票 售票窗口2售出第6张票 售票窗口2售出第7张票 售票窗口1售出第8张票 售票窗口1售出第9张票 售票窗口2售出第10张票
-
由运行结果可以看出问题得到解决,但此方法运行效率较低。
上一篇:
通过多线程提高代码的执行效率例子