在学习某马进阶视频的时候发现,其中Java程序模拟多线程同时卖票,使用三种锁方法运行时均发现票卖完后,程序不能自己结束,过了一会给出错误:超过最大锁计数。
注:修改方法在下方代码下面红色加粗字体
在这里插入图片描述

Exception in thread "Thread-2" java.lang.Error: Maximum lock count exceeded
	at java.base/java.util.concurrent.locks.ReentrantLock$Sync.nonfairTryAcquire(ReentrantLock.java:138)
	at java.base/java.util.concurrent.locks.ReentrantLock$NonfairSync.tryAcquire(ReentrantLock.java:199)
	at java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1225)
	at java.base/java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:267)
	at com.itheima.demo09.Lock.RunnableImpl.run(RunnableImpl.java:33)
	at java.base/java.lang.Thread.run(Thread.java:844)

考虑是因为没有释放锁。造成请求次数过多倍的大于获取请求次数。
即The problem is you release your semaphore more times than acquired.
下面是源代码

public class RunnableImpl implements Runnable {
    //定义一个多个线程共享的票源
    private int ticket = 100;
    //1.在成员位置创建一个ReentrantLock对象
    Lock l = new ReentrantLock();
    //设置线程任务:卖票
    @Override
    public void run() {
        //使用死循环,让卖票操作重复执行
        while (true) {
            //2.在可能会出现安全问题的代码前调用Lock接口中的方法lock获取锁
            l.lock();
            //先判断票是否存在
            if (ticket > 0) {
                //提高安全问题出现的概率,让程序睡眠
                try {
                    Thread.sleep(10);
                    //票存在,卖票 ticket--
                    System.out.println(Thread.currentThread().getName() + "-->正在卖第" + ticket + "张票");
                    ticket--;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    //3.在可能会出现安全问题的代码后调用Lock接口中的方法unlock释放锁
                    l.unlock();//无论程序是否异常,都会把锁释放
                }
            }
        }
    }
}

发现如果在售卖最后一张票的时候先获取到 l 锁,if判断语句不成立,则没有解锁语句unlock被执行,while死循环也不会停止,即程序一直在循环,但是拿到锁之后一直没有拿到解锁语句,导致Error;该Error在源码中有说明。将代码中添加else语句并在其中添加一个unlock解锁和break跳出死循环修改如下(第22行代码中体现修改)

public class RunnableImpl implements Runnable {
    private int ticket = 100;
    final Lock l = new ReentrantLock();
   int i=0;
    @Override
    public void run() {
        while (i<150) {
            l.lock();
            if (ticket > 0) {
                try {
                    Thread.sleep(10);
                    System.out.println(Thread.currentThread().getName() + "出票号:" + ticket);
                    ticket--;
                    i++;
                    System.out.println(l);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    l.unlock();
                    System.out.println(l);
                }
            } else {
                l.unlock();
                break;
            }
        }
    }
}

中间部分输出语句是为了观察锁有没有被释放。运行结果如下:
运行结果
解锁并break之后程序可以自己跳出死循环!

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐