2014-12-25 2 views
-1

У меня есть два объекта в разных потоках с использованием одного и того же байтового буфера. Они оба имеют следующий метод:Java-тупик с одним замком

synchronized(buffer) 
{ 
    ... 

    if (...) 
     buffer.wait(); 

    ... 

    buffer.notifyAll(); 

    ... 
} 

Оба объекта никогда не будут ждать в то же время. Это может привести к блокировке. Как мне это обработать?

РЕДАКТИРОВАТЬ:

Эти объекты реализации трубопроводных входных и выходных потоков.

Метод в централизованном классе выходного потока:

@Override 
public void write(byte[] b, int off, int len) throws IOException 
{ 
    synchronized(sink.buffer) 
    { 
     if (sink.writepos == sink.readpos && sink.writelap == (sink.readlap + 1)) 
     { 
      try 
      { 
       sink.buffer.wait(); 
      } 
      catch(InterruptedException e) 
      { 
       throw new IOException(e.getMessage()); 
      } 

      write(b, off, len); 
      return; 
     } 

     int amount = Math.min(len, (sink.writepos < sink.readpos ? sink.readpos : sink.buffer.length) - sink.writepos); 
     System.arraycopy(b, off, sink.buffer, sink.writepos, amount); 
     sink.writepos += amount; 

     if (sink.writepos == sink.buffer.length) 
     { 
      sink.writepos = 0; 
      sink.writelap++; 
     } 

     if (amount < len) 
      write(b, off + amount, len - amount); 
     else 
      sink.buffer.notifyAll(); 
    } 
} 

Метод в централизованном классе входного потока:

@Override 
public int read(byte[] b, int off, int len) throws IOException 
{ 
    synchronized(buffer) 
    { 
     if (readpos == writepos && readlap == writelap) 
     { 
      try 
      { 
       buffer.wait(); 
      } 
      catch(InterruptedException e) 
      { 
       throw new IOException(e.getMessage()); 
      } 

      return read(b, off, len); 
     } 

     int amount = Math.min(len, (writepos > readpos ? writepos : buffer.length) - readpos); 
     System.arraycopy(buffer, readpos, b, off, amount); 
     readpos += amount; 

     if (readpos == buffer.length) 
     { 
      readpos = 0; 
      readlap++; 
     } 

     if (amount < len) 
     { 
      int next = read(b, off + amount, len - amount); 
      return amount + next; 
     } 
     else 
     { 
      buffer.notifyAll(); 
     } 

     return amount; 
    } 
} 
+2

Мы должны знать, почему вы хотите, чтобы эти потоки, чтобы ждать, чтобы быть в состоянии правильно ответить на этот вопрос. – Vitruvius

+0

@Saposhiente Я добавил код методов. – Kalinovcic

+0

Вы предполагали, что методы должны быть рекурсивными? Вы получаете исключение стека? 'write' вызывает' write', вероятно, неопределенно? –

ответ

2

Я вставил обильное количество отладочных println отчетности в свои методы и побежал их при попытке чтения 20-буквенный массива строчного алфавита с помощью буфера 8 байт, и получил следующий результат:

Want to write abcdefghijklmnopqrst at 0 (20 chars) 
Writer synchronized 
Want to read 20 chars into      at 0 
Writing 8; now abcdefgh 
New writer lap 
Continuing write 
Want to write abcdefghijklmnopqrst at 8 (12 chars) 
Writer synchronized 
Writer waiting. 
Reader synchronized 
Read 8 into abcdefgh 
New read lap 
Continuing read 
Want to read 12 chars into abcdefgh    at 8 
Reader synchronized 
Reader waiting. 

Это показывает источник вашей проблемы: когда write или read делает лишь частичный прогресс при записи или чтении, он не уведомляет о другой теме, которую они могут теперь написать больше. Перемещение notifyAll() заявление немедленно после того, как writepos += amount и readpos += amount производит успех:

Want to read 20 chars into      at 0 
Reader synchronized 
Reader waiting. 
Want to write abcdefghijklmnopqrst at 0 (20 chars) 
Writer synchronized 
Writing 8; now abcdefgh 
Writer notifying buffer. 
New writer lap 
Continuing write 
Want to write abcdefghijklmnopqrst at 8 (12 chars) 
Writer synchronized 
Writer waiting. 
Reader resumed 
Want to read 20 chars into      at 0 
Reader synchronized 
Read 8 into abcdefgh    
Reader notifying buffer. 
New read lap 
Continuing read 
Want to read 12 chars into abcdefgh    at 8 
Reader synchronized 
Reader waiting. 
Writer resumed 
Want to write abcdefghijklmnopqrst at 8 (12 chars) 
Writer synchronized 
Writing 8; now ijklmnop 
Writer notifying buffer. 
New writer lap 
Continuing write 
Want to write abcdefghijklmnopqrst at 16 (4 chars) 
Writer synchronized 
Writer waiting. 
Reader resumed 
Want to read 12 chars into abcdefgh    at 8 
Reader synchronized 
Read 8 into abcdefghijklmnop  
Reader notifying buffer. 
New read lap 
Continuing read 
Want to read 4 chars into abcdefghijklmnop  at 16 
Reader synchronized 
Reader waiting. 
Writer resumed 
Want to write abcdefghijklmnopqrst at 16 (4 chars) 
Writer synchronized 
Writing 4; now qrstmnop 
Writer notifying buffer. 
Write finished. 
Reader resumed 
Want to read 4 chars into abcdefghijklmnop  at 16 
Reader synchronized 
Read 4 into abcdefghijklmnopqrst 
Reader notifying buffer. 
Read finsihed. 
Read 20 chars 
Read abcdefghijklmnopqrst 
0

У вас есть то и ждет, чтобы получать уведомления. Не оставляя никаких других потоков, чтобы уведомить их, вы не можете одновременно ждать. Вы должны убедиться, что условие в операторе if не может быть истинным для обоих потоков одновременно.

Смежные вопросы