2017-02-19 37 views
0

我有一个的FileReader类,这是这样的Java的等待两个线程通知作为同一类

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(); 
} 

那么,有什么问题?

在此先感谢

+0

你的锁在哪里?你如何获得它们?请包括你所有的课程。 – ram

+0

@ram我编辑了我的文章。我的锁在FileReader类中,但onDone函数在其他地方(在我的主类中) – strings95

+0

'lock.wait()'你的运行代码在该行,并且你永远不会显示你在哪里调用next()' – nachokk

回答

1

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

只是假设下面的程序流程:

  1. 你开始reader1螺纹
  2. 你开始reader2螺纹

在一段时间内这两个线程的一个开始。假设reader1线程开始第一:

  1. 它同步到其lock对象
  2. 它从文件中读取
  3. 它调用其回调线,即呼吁reader1reader2next()。此呼叫成功(但实际上是非操作)
  4. 它在其lock对象上调用wait。并等待...

在一段时间以后reader2线程开始

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

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

0

要调用监听器回调,同时保持相同的对象lock上的锁。这将允许在等待被调用之前调用通知。这会让你的线程永远等待。

你也应该

  1. 使用java.util.CountDownLatch这个问题。
  2. 使用ThreadPool。从线程扩展是老办法,容易出错。
  3. 您同步 next()方法
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循环中。