Java等待通知将两个线程作为同一个类

时间:2017-02-19 15:23:21

标签: java multithreading

我有一个类似这样的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();
        }
    }
}

}

我有两个这个FileReader的实例,因为我想同时逐行读取两个文件。问题是我的代码只读取两个文件中的一行,然后它会暂停。

我在回调中调用该函数,如此

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

那么问题是什么?!

提前致谢

3 个答案:

答案 0 :(得分:1)

您同步lock方法的next()对象也会在while方法的run循环中使用。因此,无法从另一个线程中调用next()方法的代码。

假设以下程序流程:

  1. 您启动reader1主题
  2. 您启动reader2主题
  3. 在某个时候,这两个线程中的一个开始。我们假设首先开始reader1线程:

    1. 它与lock对象
    2. 同步
    3. 它从文件中读取一行
    4. 它会调用其回调,即在next()reader1上调用reader2。此调用成功(但实际上是无操作)
    5. wait对象上调用lock。并等待......
    6. 以后reader2线程开始

      1. 它与lock对象
      2. 同步
      3. 它从文件中读取一行
      4. 它调用它的回调,但是,当调用reader1.next()时,它尝试从另一个线程同步到reader1lock对象,从而使程序进入死锁状态。 / LI>

        为了解决这个问题,我真的建议过度执行逐行同步的概念。一个简单的解决方法可能是为next()方法使用不同的锁变量。

答案 1 :(得分:0)

在对同一个对象lock持有锁定时,您正在调用侦听器回调。这将允许在调用wait之前调用notify。这将使你的线程永远等待。

你应该,

  1. 使用java.util.CountDownLatch解决此问题。
  2. 使用ThreadPool。从线程扩展是做旧的方式并且容易出错。

答案 2 :(得分:0)

您正面临着经典的死锁情景。让第一个锁为lock1,第二个锁为lock2。在您的第一个实例中,锁定状态可以表示如下:

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

    }
    synchronized (lock2) {

    }
    // end of onDone
}

在第二个中,它是这样的:

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

    }
    synchronized (lock2) {

    }
    // end of onDone
}

您应该像其他答案所暗示的那样优化您的逻辑。

您设计的另一个缺陷是;你也没有考虑可能的虚假唤醒。通常,您应该将wait()来电置于while循环中。

相关问题