从售票模拟浅谈线程安全问题

初步编写售票程序

  1. 定义票数临界区,实现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-- ;
    }
}
  1. 定义两个线程共享临界区同时进行售票操作(写操作)
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() ;
  1. 用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张票
  • 由运行结果可以看出问题得到解决,但此方法运行效率较低。

猜你喜欢

转载自blog.csdn.net/u013634252/article/details/80535969