简体   繁体   中英

Java wait notify with two threads as same class

I have a FileReader class which is like this

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. 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. Therefore, the code of your next() method cannot be called from within another thread.

Just assume the following program flow:

  1. You start reader1 thread
  2. You start reader2 thread

At some time one of those two threads start. Let's assume reader1 thread starts first:

  1. It syncs to its lock object
  2. It reads a line from the file
  3. It calls its callback, ie calls next() on reader1 and reader2 . This call is successful (but actually a no-op)
  4. It calls wait on its lock object. And waits...

At some later time the reader2 thread starts

  1. It syncs to its lock object
  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.

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.

You are calling listener call back while holding the lock on the same object 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.
  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 . 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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