You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java多线程售票示例异常:仅单个线程执行售票逻辑求助

Java多线程售票示例仅单个线程执行的问题解决

我编写了一个Java多线程售票示例,但运行后发现只有单个线程完成了全部售票操作。

原代码

public class test2 {
    public static void main(String[] args) {
        per per = new per();
        Thread t1 = new Thread(per);
        Thread t2 = new Thread(per);
        Thread t3 = new Thread(per);
        t1.start();
        t2.start();
        t3.start();
    }
}

class per implements Runnable {
    int ticket = 10;
    final String a = "";

    @Override
    public void run() {
        while (true) {
            synchronized(a) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + " ticket " + ticket);
                    ticket--;
                }
            }
        }
    }
}

实际运行结果

Thread-1 ticket 9
Thread-1 ticket 8
Thread-1 ticket 7
Thread-1 ticket 6
Thread-1 ticket 5
Thread-1 ticket 4
Thread-1 ticket 3
Thread-1 ticket 2
Thread-1 ticket 1
Thread-1 ticket 0

问题原因

  1. 锁对象不合理:用空字符串""作为锁对象,虽然是final修饰,但空字符串属于Java常量池全局共享实例,锁的语义不清晰,还可能引发意外的锁冲突。
  2. 线程调度偏向:线程释放锁后会立刻进入下一轮while循环抢锁,操作系统调度可能优先让刚释放锁的线程再次获取锁,导致其他线程抢锁机会被压制。
  3. 无循环退出逻辑:票售罄后线程仍会无限循环尝试抢锁,完全是无效的资源消耗。

修复后的代码

public class TicketSaleTest {
    public static void main(String[] args) {
        TicketSeller seller = new TicketSeller();
        Thread t1 = new Thread(seller, "售票窗口1");
        Thread t2 = new Thread(seller, "售票窗口2");
        Thread t3 = new Thread(seller, "售票窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}

class TicketSeller implements Runnable {
    private int ticket = 10;

    @Override
    public void run() {
        while (true) {
            // 用当前共享的Runnable实例作为锁,语义明确且安全
            synchronized (this) {
                if (ticket <= 0) {
                    // 票卖完直接退出循环,停止抢锁
                    break;
                }
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " 售出第 " + ticket + " 张票");
                ticket--;
            }
            // 主动让步,给其他线程抢锁机会,让多线程效果更明显
            Thread.yield();
        }
    }
}

修复要点

  • 替换锁对象为this,利用共享的Runnable实例作为锁,避免常量池锁的潜在问题。
  • 添加ticket <= 0的退出条件,终止无效的循环抢锁行为。
  • 在同步块结束后调用Thread.yield(),主动让当前线程放弃CPU执行权,提升其他线程抢锁的概率,保证多线程售票的效果。

内容的提问来源于stack exchange,提问作者Sihan Adi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 12:45:47