两个线程正在等待,无法解决

时间:2016-12-24 17:37:06

标签: java multithreading

有两种方法可以将消息推送到arraylist,而其他方法则从arraylist中检索消息。两种方法都是同步的。 我创建了两个线程,一个用于将消息推送到arraylist,另一个用于检索。两个线程处于死锁状态。如何解决它

以下是推送和显示消息的代码

public class FetchCurrentTime {

    static final int MAXMESSAGE = 5;
    private List<String> messages = new ArrayList<String>();

    public synchronized void putTime(){
        while(messages.size() != MAXMESSAGE){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
            Calendar cal = Calendar.getInstance();
            messages.add(dateFormat.format(cal.getTime()).toString());
        }
        notify();

    }

    public synchronized String getTime(){
        String message= "Unable to fetch time";
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(!message.isEmpty()){
        message = messages.remove(messages.size()-1);
        }
        notify();
        return message;
    }

}

以下是生产者和消费者代码

public class ProduceTime extends Thread {
    FetchCurrentTime fc ;

    public ProduceTime(FetchCurrentTime fc) {
            this.fc = fc;
    }

    @Override
    public void run() {
        fc.putTime();
    }

}


public class ConsumeTime extends Thread {
    FetchCurrentTime fc ;
    public ConsumeTime(FetchCurrentTime fc) {
        this.fc = fc;
    }

    @Override
    public void run() {
        while (true) {
            String time = fc.getTime();
            System.out.println(time);
        }
    }

}

这是要测试的代码。

public class GetDate {

    public static void main(String[] args) throws InterruptedException {
        FetchCurrentTime fc = new FetchCurrentTime();
        ProduceTime p = new ProduceTime(fc);
        ConsumeTime c = new ConsumeTime(fc);

        Thread t1 = new Thread(p);
        Thread t2 = new Thread(c);

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

}

3 个答案:

答案 0 :(得分:0)

我发现问题出在wait()getTime()中调用putTime()时,因为两者都在等待另一个通知;从未发生过。 此外,getTime()中存在拼写错误,应该是messages.isEmpty()(列表)而不是message.isEmpty()(字符串)

您可以尝试使用此代码。请注意,它会永远运行,因此您需要处理终止条件。

public synchronized void putTime() {

    while (true) {  // To ensure list contains 5 elements at any point of time before removal
        if (messages.size() >= MAXMESSAGE) {
            try {
                wait(); // wait issued only when list is full
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
        }

        while (messages.size() < MAXMESSAGE) {
            DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
            Calendar cal = Calendar.getInstance();
            messages.add(dateFormat.format(cal.getTime()).toString());
        }

        notify();   // notify getTime() to resume execution
    }
}

public synchronized String getTime() {
    String message = "Unable to fetch time";

    try {
        Thread.sleep(100);  // adding delay to help see the output

        if (messages.isEmpty()) {
            wait(); // wait for putTime() to add messages to the list
        }

        if (!messages.isEmpty()) {
            message = messages.remove(messages.size() - 1);
            notify();   // notifies putTime() to add a message to the list; helps keep count to 5
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    return message;
}

也就是说,建议使用高级的Thread构造,它有助于实现相同(更容易)和更好的吞吐量。

希望这会有所帮助:)

答案 1 :(得分:0)

请在您的代码中找到以下问题。

  1. 为生产者提供生成编号的初始时间,因此在消费者线程中包括Thread.sleep(100)。
  2. 线程必须在以下条件下使用wait()。
    一种)。使用者线程-仅当array.size()为零时才使用wait()。
    b)。生产者线程-仅当array.size()> = MAX_SIZE时才需要wait()。

注意-使用notifyAll而不是notify。

答案 2 :(得分:-1)

有很多方法可以解决这个问题。每当有两个或多个锁由两个不同的订单中的线程获取时,就会发生死锁。订购是关键部分。

E.g。如果一个线程可以获得put锁定,而另一个线程获取get锁定,反之亦然,那就是死锁。如果每个线程总是首先获取get lock,那么put lock,并在释放get lock之前释放put lock,然后就不可能出现死锁。

要解决这个问题,请使锁明确(例如:synchronized(lockObject){/ *代码* /}),并始终按顺序获取锁,或者只使用一个锁。

另一个解决方案是使用像Akka这样的actor框架。演员抽象锁定,特别适合发送和接收消息。有了演员,就有一个&#34;邮箱&#34;使用同步访问来添加来自其他线程的消息,但是actor本身在其一个线程中串行处理消息。