带有一个锁的Java死锁

时间:2014-12-25 01:06:23

标签: java multithreading thread-safety deadlock

我使用相同的字节缓冲区在不同的线程中有两个对象。他们都有以下方法:

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 个答案:

答案 0 :(得分:2)

我在你的方法中插入了大量的调试println语句,并尝试通过8字节缓冲区读取小写字母的20个字母数组,并得到以下输出:

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.

这揭示了您的问题的根源:当writeread在写入或阅读时仅取得部分进展时,它不会通知另一个线程他们现在可以写更多内容。将notifyAll()语句移至writepos += amountreadpos += 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

答案 1 :(得分:0)

然后你们都等着收到通知。没有其他线程通知他们,你不能让两个人同时等待。您必须确保if语句中的条件不能同时为两个线程都为真。