Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/364.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
带一个锁的Java死锁_Java_Multithreading_Thread Safety_Deadlock - Fatal编程技术网

带一个锁的Java死锁

带一个锁的Java死锁,java,multithreading,thread-safety,deadlock,Java,Multithreading,Thread Safety,Deadlock,我有两个对象在不同的线程中使用相同的字节缓冲区。它们都有以下方法: synchronized(buffer) { ... if (...) buffer.wait(); ... buffer.notifyAll(); ... } 两个对象永远不会同时等待。 这可能会导致死锁。我怎么处理 编辑: 这些对象是管道输入和输出流的实现 管道输出流类中的方法: @Override public void write(byte[] b, in

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

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;
    }
}
@覆盖
公共无效写入(字节[]b,int off,int len)引发IOException
{
已同步(sink.buffer)
{
if(sink.writepos==sink.readpos&&sink.writelap==(sink.readlap+1))
{
尝试
{
sink.buffer.wait();
}
捕捉(中断异常e)
{
抛出新IOException(例如getMessage());
}
注销(b,注销,len);
返回;
}
int amount=Math.min(len,(sink.writepos
管道输入流类中的方法:

@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;
    }
}
@覆盖
公共整数读取(字节[]b,整数关闭,整数长度)引发IOException
{
已同步(缓冲区)
{
if(readpos==writepos&&readlap==writelap)
{
尝试
{
buffer.wait();
}
捕捉(中断异常e)
{
抛出新IOException(例如getMessage());
}
返回读数(b、off、len);
}
int amount=Math.min(len,(writepos>readpos?writepos:buffer.length)-readpos);
系统阵列复制(缓冲区、读取位置、b、关闭、金额);
readpos+=金额;
if(readpos==buffer.length)
{
readpos=0;
readlap++;
}
如果(金额
然后你们两人都在等待通知。不让其他线程通知它们,不能让两个线程同时等待。您必须确保if语句中的条件不能同时适用于两个线程。

我在您的方法中插入了大量调试
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.
这揭示了问题的根源:当
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

我们需要知道为什么您希望这些线程等待能够正确回答这个问题。@Saposhiente我添加了这些方法的代码。您是否希望这些方法是递归的?您是否收到堆栈异常
write
调用
write
,可能是无限期的?@SanjayManohar是的,这些方法旨在递归<代码>写入
不会无限期调用。