繁体   English   中英

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

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

我有一个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();
}

所以有什么问题?!

提前致谢

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

只需假设以下程序流程:

  1. 您启动reader1线程
  2. 您启动reader2线程

在某些时候,这两个线程之一开始。 假设reader1线程首先启动:

  1. 它同步到其lock对象
  2. 它从文件中读取一行
  3. 它调用其回调,即在reader1reader2上调用next() 通话成功(但实际上没有操作)
  4. 它在其lock对象上调用wait 等等...

在稍后的时间, reader2线程启动

  1. 它同步到其lock对象
  2. 它从文件中读取一行
  3. 它调用其回调,但是,当调用reader1.next()它将尝试从其他线程将其lock对象同步到reader1 ,从而使程序进入死锁状态。

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

您正在将侦听器回叫,同时将锁定保持在同一对象lock 这将允许在调用等待之前调用通知。 这将使您的线程永远等待。

你应该,

  1. 使用java.util.CountDownLatch解决此问题。
  2. 使用线程池。 从线程扩展是执行此操作的旧方法,并且容易出错。

您正面临经典的僵局情况。 假设第一锁为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循环中。

暂无
暂无

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

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