wudixiaowangjava 2013-10-19 05:51 采纳率: 0%
浏览 964

java 模拟线程死锁实验

我想两个线程一直在售票知道票卖光,但是用while()控制循环后出现
售票2进入共享区
当前没有车票可以出售!
售票2进入共享区
当前没有车票可以出售!
售票2进入共享区
.....
具体代码如下
package com;
public class SaleThread extends Thread{
private String name;
ShareResource shareresource;
public SaleThread(){}
public SaleThread(String threadname){ //初始化线程名称的构造函数
this.name=threadname;
}
public SaleThread(String threadname,ShareResource shareresource1){//初始化共享区和线程名称
this.name=threadname;
shareresource=shareresource1;

}
public void run(){
//synchronized (shareresource){
while(shareresource.currentticket>=0){
if(this.shareresource.isAccessed()){
System.out.println(this.name+"进入共享区");
shareresource.changeAccess(); //禁止其他的线程进入共享区
//while(shareresource.currentticket>=0&&this.shareresource.isAccessed()){
if(shareresource.isEmpty()){
System.out.println("当前没有车票可以出售!");
shareresource.changeAccess(); //操作完毕退出共享区,其他线程可以进入
}else{
shareresource.currentticket--;
System.out.println(name+"正在售出一张车票,"+"还剩下"+shareresource.currentticket+"张票。");
shareresource.changeAccess(); //操作完毕退出共享区,其他线程可以进入
}
} //if 结束

else{
try{
shareresource.wait(100); //共享区不能进入该线程等待100ms
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
//}
}
}
package com;

public class ShareResource {
public int currentticket;
public boolean isaccessed=true;
public ShareResource(){}
public ShareResource(int ticketnum){ //初始化共享区里的车票数
this.currentticket=ticketnum;
}
public void setShareResource(int cticket){ //重置共享区里的车票数
this.currentticket=cticket;
}
public boolean isEmpty(){ //判断共享区是否为空
if(currentticket>0) return false;
return true;
}
public boolean isAccessed(){ //判断共享区能否进入
if(isaccessed) return true;
else return false;
}
public void changeAccess(){ //改变共享区状态
this.isaccessed=!isaccessed;
}
public static void main(String[] args){
ShareResource shareresource=new ShareResource(10);
SaleThread salethread1=new SaleThread("售票1",shareresource);
SaleThread salethread2=new SaleThread("售票2",shareresource);
salethread1.start();
salethread2.start();

}

}

  • 写回答

1条回答

  • ChatGPTᴼᴾᴱᴺᴬᴵ 2023-09-05 21:31
    关注

    该回答引用ChatGPT-3.5,仅为您供参考,不保证完全正确
    你的代码存在一些问题,导致了死锁的情况。死锁通常发生在多个线程试图获取多个锁并且彼此互相等待的情况下。在你的代码中,两个线程都试图获取shareresource对象的锁,并且在changeAccess方法中释放锁,但是这并没有解决潜在的死锁问题。


    为了解决这个问题,你可以考虑使用java.util.concurrent包中的ReentrantLock来管理锁,这样可以更灵活地控制线程的进入和退出。以下是一个修改后的示例代码:

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class SaleThread extends Thread {
        private String name;
        private ShareResource shareresource;
        private Lock lock;
    
        public SaleThread(String threadname, ShareResource shareresource) {
            this.name = threadname;
            this.shareresource = shareresource;
            this.lock = new ReentrantLock();
        }
    
        public void run() {
            while (shareresource.getCurrentTicket() > 0) {
                lock.lock();
                try {
                    if (shareresource.getCurrentTicket() > 0) {
                        System.out.println(name + "正在售出一张车票, 还剩下" + shareresource.getCurrentTicket() + "张票。");
                        shareresource.setCurrentTicket(shareresource.getCurrentTicket() - 1);
                    } else {
                        System.out.println("当前没有车票可以出售!");
                    }
                } finally {
                    lock.unlock();
                }
            }
        }
    
        public static void main(String[] args) {
            ShareResource shareresource = new ShareResource(10);
            SaleThread salethread1 = new SaleThread("售票1", shareresource);
            SaleThread salethread2 = new SaleThread("售票2", shareresource);
            salethread1.start();
            salethread2.start();
        }
    }
    
    class ShareResource {
        private int currentTicket;
    
        public ShareResource(int ticketnum) {
            this.currentTicket = ticketnum;
        }
    
        public int getCurrentTicket() {
            return currentTicket;
        }
    
        public void setCurrentTicket(int currentTicket) {
            this.currentTicket = currentTicket;
        }
    }
    

    在这个示例中,我们使用了ReentrantLock来管理共享资源的访问,确保只有一个线程能够进入临界区。这可以避免死锁问题,并且更加可控。同时,我们使用try-finally块来确保在任何情况下都会释放锁。这样可以确保即使发生异常,锁也会被释放,不会导致其他线程被永久阻塞。


    该回答引用NewBing,仅为您供参考,不保证完全正确
    你好,这是Bing。我看了你的代码,发现你可能出现了线程死锁的问题。线程死锁是指两个或多个线程互相持有对方所需要的资源(锁),都在等待对方释放资源而无法继续执行的情况¹。你的代码中,两个售票线程都在同步代码块中使用了wait()方法,这会导致线程释放当前持有的锁,进入等待状态²。如果两个线程同时进入wait(),那么就会发生死锁,因为没有其他线程能够唤醒它们。为了避免这种情况,你可以使用notify()或notifyAll()方法来唤醒等待的线程²。你可以在每次释放锁之前调用这些方法,例如:

    synchronized (accountFrom) {
      synchronized (accountTo) {
        // 转账逻辑
      }
      accountTo.notify(); // 唤醒等待accountTo的线程
    }
    accountFrom.notify(); // 唤醒等待accountFrom的线程
    

    这样可以保证至少有一个线程能够继续执行,从而避免死锁。当然,这种方法并不是最优的,因为它可能会导致频繁的上下文切换和性能损耗。更好的方法是使用java.util.concurrent包中提供的高级并发工具,例如ReentrantLock、Semaphore、CountDownLatch等³。这些工具可以提供更灵活和高效的同步机制,避免使用低级的wait()和notify()方法。


    源: 与必应的对话, 2023/9/5
    (1) Java 实例 – 死锁及解决方法 | 菜鸟教程. https://www.runoob.com/java/thread-deadlock.html.
    (2) Java中各种死锁详细讲述及其解决方案(图文并茂,浅显易懂) - 知乎. https://zhuanlan.zhihu.com/p/385855265.
    (3) Java 死锁的原理详解以及检测和解决死锁的方法 - 掘金. https://juejin.cn/post/7019476990302355470.

    评论

报告相同问题?

悬赏问题

  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥30 用arduino开发esp32控制ps2手柄一直报错
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题
  • ¥15 Visual Studio问题
  • ¥20 求一个html代码,有偿