好菜哦 2024-08-03 23:38 采纳率: 0%
浏览 1

java多线程问题,synchronized、wait相关

定义一个TicketTest.java文件,文件中的代码如下:


public class TicketTest {
    public static void main(String[] args) {
        Ticket ticket = new Ticket(100);

        Runnable task = ()->{
            while (true){
                    ticket.sellTicket();
            }
        };

        Thread t1 = new Thread(task);
        t1.setName("窗口1");
        Thread t2 = new Thread(task);
        t2.setName("窗口2");
        Thread t3 = new Thread(task);
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }
}

class Ticket {
    private int number;

    public Ticket(int number) {
        this.number = number;
    }
    
    public synchronized void sellTicket() {
        System.out.println(Thread.currentThread().getName()+"拿到sellTicket锁");
        try {
            Thread.currentThread().wait(10); // 释放锁
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

这段代码运行以后,会报java.lang.IllegalMonitorStateException的异常,就是在wait(10)这里报的错,不明白,wait方法是在synchronized方法中执行的,线程有锁啊,为什么会报这个错误,青椒一下

  • 写回答

1条回答 默认 最新

  • 专家-司宇[在线] 2024-08-03 23:38
    关注

    引自免费微信小程序:皆我百晓生

    首先,让我们理解一下java.lang.IllegalMonitorStateException这个异常。这个异常通常在你尝试在未持有对象锁的情况下调用wait(), notify(), 或 notifyAll()方法时抛出。换句话说,这些方法必须在同步块或者同步方法中调用,以确保当前线程持有对象的锁。

    在你提供的代码中,Ticket类的sellTicket方法被标记为synchronized,这意味着每次只有一个线程可以执行这个方法。然而,问题出在wait()方法的调用上。在wait()被调用时,当前线程必须持有对象的锁(也就是必须是那个对象的监视器线程)。然而在你的代码中,当调用wait(10)时,线程并没有持有Ticket对象的锁。所以这就导致了java.lang.IllegalMonitorStateException异常。

    为了解决这个问题,你需要确保在调用wait()方法时,当前线程已经获取了锁。这可以通过确保调用wait()方法在synchronized块内完成来实现。这样,只有持有锁的线程才能进入这个块并调用wait()方法。这里有一个修正后的版本:

    class Ticket {
        private int number;
        private int maxNumber; // 添加这个变量来模拟售票数量限制
    
        public Ticket(int number) {
            this.number = number;
            this.maxNumber = number; // 设置售票的最大数量
        }
        
        public synchronized void sellTicket() {
            System.out.println(Thread.currentThread().getName()+"拿到sellTicket锁");
            while (number > 0) { // 添加这个循环来确保不会超出售票的最大数量限制
                try {
                    Thread.currentThread().wait(10); // 在这里调用wait()方法,确保当前线程持有锁
                    System.out.println(Thread.currentThread().getName() + "卖出票数:" + number--);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    现在,每个线程在尝试卖出票之前都会等待其它线程完成卖出票的操作(通过调用wait()方法)。当票的数量减少到零时,其他线程会收到通知(通过调用notify()notifyAll()方法),然后可以继续卖出票。这样就能避免多个线程同时卖出票数超过总票数的情况。同时,由于我们在同步块内调用wait()方法,所以不会抛出java.lang.IllegalMonitorStateException异常了。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 8月3日