简体   繁体   English

Java等待通过两个线程作为同一类进行通知

[英]Java wait notify with two threads as same class

I have a FileReader class which is like this 我有一个FileReader类,像这样

public class FileReader extends Thread
{

private final Object lock = new Object();

public FileReader(String path, FileReaderCallback callback)
{
    super(path);

    this.path = path;
    this.callback = callback;
}

@Override
public void run()
{
    try
    {
        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
        String info;

        while ((info = reader.readLine()) != null)
        {
                synchronized (lock)
                {
                    callback.onDone(path, info);

                    try
                    {
                        lock.wait();
                    }
                    catch (Exception ignored)
                    {
                    }
                }
            }
        }
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }
}

public void next()
{
    synchronized (lock)
    {
        try
        {
            lock.notify();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

}

And I have two instance of this FileReader because I want to read two file line by line simultaneously. 我有这个FileReader的两个实例,因为我想同时逐行读取两个文件。 The problem is my code only reads one line from both file and then it's going to pause. 问题是我的代码仅从两个文件读取一行,然后将暂停。

I Call the function on my callback like this 我这样在我的回调上调用该函数

public void onDone(String path, String info)
{
    reader1.next();
    reader2.next();
}

So what's the problem?! 所以有什么问题?!

Thanks in advance 提前致谢

Your lock object which you synchronize the next() method to is also used within your while loop in the run method. next()方法同步的lock对象也可以在run方法的while循环中使用。 Therefore, the code of your next() method cannot be called from within another thread. 因此,不能从另一个线程中调用next()方法的代码。

Just assume the following program flow: 只需假设以下程序流程:

  1. You start reader1 thread 您启动reader1线程
  2. You start reader2 thread 您启动reader2线程

At some time one of those two threads start. 在某些时候,这两个线程之一开始。 Let's assume reader1 thread starts first: 假设reader1线程首先启动:

  1. It syncs to its lock object 它同步到其lock对象
  2. It reads a line from the file 它从文件中读取一行
  3. It calls its callback, ie calls next() on reader1 and reader2 . 它调用其回调,即在reader1reader2上调用next() This call is successful (but actually a no-op) 通话成功(但实际上没有操作)
  4. It calls wait on its lock object. 它在其lock对象上调用wait And waits... 等等...

At some later time the reader2 thread starts 在稍后的时间, reader2线程启动

  1. It syncs to its lock object 它同步到其lock对象
  2. It reads a line from the file 它从文件中读取一行
  3. It calls its callback, however, when calling reader1.next() it tries to synchronize to the reader1 its lock object from a different thread, thus putting your program into a deadlock state. 它调用其回调,但是,当调用reader1.next()它将尝试从其他线程将其lock对象同步到reader1 ,从而使程序进入死锁状态。

To solve this problem I would really suggest to overwork the concept of how you perform the line-by-line synchronization. 为了解决此问题,我真的建议您过度处理如何逐行同步的概念。 An easy fix would probably be to use a different lock variable for your next() method. 一个简单的解决方法可能是对next()方法使用不同的锁变量。

You are calling listener call back while holding the lock on the same object lock . 您正在将侦听器回叫,同时将锁定保持在同一对象lock This will allow notify to be invoked before a wait is invoked. 这将允许在调用等待之前调用通知。 This will make your thread wait forever. 这将使您的线程永远等待。

You should, 你应该,

  1. Use java.util.CountDownLatch for this problem. 使用java.util.CountDownLatch解决此问题。
  2. Use ThreadPool. 使用线程池。 Extending from thread is old way of doing it and prone to errors. 从线程扩展是执行此操作的旧方法,并且容易出错。

You are facing a classic deadlock scenario. 您正面临经典的僵局情况。 Let the first lock be lock1 and the second lock be lock2 . 假设第一锁为lock1 ,第二锁为lock2 In your first instance, the lock status can be expressed as follows: 在您的第一个实例中,锁定状态可以表示为:

synchronized (lock1) {
    // start of onDone
    synchronized (lock1) {

    }
    synchronized (lock2) {

    }
    // end of onDone
}

and in second one, it is like this: 在第二个中,它是这样的:

synchronized (lock2) {
    // start of onDone
    synchronized (lock1) {

    }
    synchronized (lock2) {

    }
    // end of onDone
}

You should refine your logic, as other answers suggest. 正如其他答案所建议的那样,您应该完善自己的逻辑。

Another flaw in your design is; 设计中的另一个缺陷是: you are also not considering possible spurious wakeups. 您也没有考虑可能的虚假唤醒。 Generally, you should put your wait() calls in a while loop. 通常,您应该将wait()调用放入while循环中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM