初步编写售票程序
- 定义票数临界区,实现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张票
- 由运行结果可以看出问题得到解决,但此方法运行效率较低。