首页 > Java多线程处理同一个资源时,线程几乎不交替运行

Java多线程处理同一个资源时,线程几乎不交替运行

Java学习中,目前在看多线程
所调试的例题是经典的多点售票程序
为了防止售票点因为资源不同步的原因,而卖出超过实际票数的票
则使用了synchronized关键字
结果的确不会再卖出-1票了
但是调试结果貌似不太理想,如果票数少,就基本上是第一个售票点卖完了
即便票数多(100张),线程也不是交替运行,而是一时全A,一时全B

请帮忙查看代码是否有错,逻辑是否合理
谢谢!

代码:

class Test24_04 implements Runnable{
    private int piao = 10;
    public void run(){
        while(this.piao > 0){
            this.fun();
        }
    }
    public synchronized void fun(){
        if(this.piao > 0){
            try{
                Thread.sleep(100);
            }catch(Exception e){
                ;
            }
            System.out.println(Thread.currentThread().getName() + " 卖票了,剩余票数:" + (this.piao--));
        }
    }
}

public class JavaTest24_04{
    public static void main(String args[]){
        Test24_04 t = new Test24_04();
        Thread t1 = new Thread(t,"售票点A");   
        Thread t2 = new Thread(t,"售票点B");   
        Thread t3 = new Thread(t,"售票点C");
        t1.start(); 
        t2.start(); 
        t3.start(); 
    }
}


//使用synchroized关键字实现线程对资源的同步操作

个人理解:程序中有三种种线程,一种是Running线程,一种是Runnable线程,另一种是blocked线程,要竞争锁的线程都是处于Running状态才能有资格有能力去询问锁并竞争锁,以你的代码为例,如果你cpu是单核,第一个进入Running状态的线程只有一个,t1或t2或t3,假设为t1第一个进入,它就毫无疑问有资格获得锁,t1在运行态的时候,cpu的竞争对手为t2和t3,这个竞争不关锁问题,t2和t3都可以在t1执行那个方法的时候获得cpu试用权,假设是t2第二个获得cpu使用权,进入Running状态,这时候它就会发现锁被人拿走了,于是进入Blocked状态,同理t3也可以Running,进入Blocked状态(而且,你在t1运行fun方法里面加了sleep,更确保他们都获得过cpu使用权,从而进入了Blocked状态)。当t1执行完方法,释放了锁,blocked的t2和t3就被唤醒了,进入Runable状态,但是,t1由于一直处于Running状态(因为没有其他竞争cpu的线程,而且在t2和t3被唤醒前,也处于Running状态),所以理所当然又再一次获得了锁,刚进入Runnable状态的t2和t3只能望锁兴叹,他们后来肯定也在t1 sleep的时候或者其他时间获取过Cpu使用权,但是结果都是被打入Blocked大牢。所以t1可以一直占据锁。


看起来是涉及到java内部底层实现. 似乎thread刚释放monitor锁之后立刻去再申请, 得到monitor的机会更大一些.

把sleep()放在run()里 就避免了这样的问题, 可以得到想要的结果.

public void run(){
    while(this.piao > 0){
        this.fun();
        try{
            Thread.sleep(100);
        }catch(Exception e){}
    }
}

public synchronized void fun(){
    if(this.piao > 0)
        System.out.println(Thread.currentThread().getName() + " 卖票了,剩余票数:" + (this.piao--));
}

建议使用阻塞式队列来处理这个问题票是一张一张买的,
如果没人买票,队列处于等待状态;
当有人要票时,某个售票点(一个线程)去问队列中有没有余票,如果有(也就是队列中能取到数据),此售票点执行相关的业务逻辑;无票,就提示没有余票。
拿到票的某个售票点如取消了售票动作(客户不想要了,或付款出现问题,或付款超过自动时间或其他问题),把票再返回到队列中,供其他售票点来获取


代码是没问题的,这个demo主要是多线程同步的问题,关于线程阻塞时的选择是JVM内部算法实现的,这个应该是随机的,但是不是绝对意义上的随机,就不清楚了

【热门文章】
【热门文章】