【问题标题】:Are these Java Threads in dealock? [duplicate]这些 Java 线程是否处于解除锁定状态? [复制]
【发布时间】:2015-04-21 16:58:21
【问题描述】:

我编写了一个示例程序来说明使用管道是线程的。我创建了 2 个线程。

  1. Thread1 正在发送“Hi this is thread1”并调用 wait() 以完成线程 2。

  2. Thread2 正在打印 thread1 发送的消息,同时也会追加到一个字符串缓冲区中,然后一旦收到整个消息,线程 2 将打印字符串缓冲区的内容并调用 notify。现在调用 wait() 并通知两个线程后往往会陷入死锁

奇怪的是,thread2 打印了消息一但不打印字符串缓冲区的内容。

package com.tuto.MultiThreading;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class PipeExample {

    public static void main(String[] args) throws IOException, InterruptedException {
        final Object obj=new Object();
        final PipedOutputStream pipeoutstream=new PipedOutputStream ();
        final PipedInputStream pipeinputstream=new PipedInputStream(pipeoutstream);

        Thread thread1= new Thread(new Runnable()
        {

            public void run() {
                try {
                    pipeoutstream.write("Hello I am thread1".getBytes());
                    synchronized (obj) 
                    {

                        obj.wait(); 
                    }

                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                finally
                {
                    try {
                        pipeoutstream.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }   
                }

            }

        });


          Thread thread2 = new Thread(new Runnable() {
                public void run() {
                    try {

                        int data = pipeinputstream.read();
                        StringBuffer sb=new StringBuffer();
                        while(data != -1){
                            System.out.print((char) data);
                            sb.append((char)data);
                            data = pipeinputstream.read();
                        }
                        System.out.println();
                        System.out.println(sb.toString());
                        synchronized (obj) {

                            obj.notify();
                        }

                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    finally
                    {
                        try {
                            pipeinputstream.close();
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }   
                    }
                }
            });

        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.exit(1);
    }
}

输出:: 你好我是thread1

更新分辨率:

package com.tuto.MultiThreading;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

public class PipeExample {

    public static void main(String[] args) throws IOException, InterruptedException {
        final Object obj=new Object();
        final PipedOutputStream pipeoutstream=new PipedOutputStream ();
        final PipedInputStream pipeinputstream=new PipedInputStream(pipeoutstream);

        Thread thread1= new Thread(new Runnable()
        {

            public void run() {
                try {
                    pipeoutstream.write("Hello I am thread1".getBytes());


                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                finally
                {
                    try {
                        pipeoutstream.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }   
                    synchronized (obj) 
                    {

                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }   
                    }
                }

            }

        });


          Thread thread2 = new Thread(new Runnable() {
                public void run() {
                    try {

                        int data = pipeinputstream.read();
                        StringBuffer sb=new StringBuffer();
                        while(data != -1){
                            System.out.print((char) data);
                            sb.append((char)data);
                            data = pipeinputstream.read();
                        }
                        System.out.println();
                        System.out.println(sb.toString());
                        synchronized (obj) {

                            obj.notify();
                        }

                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    finally
                    {
                        try {
                            pipeinputstream.close();
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }   
                    }
                }
            });

        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.exit(1);
    }
}

现在我有点困惑。我只是将 wait() 从 try catch 移到 finally。对 Pipestream 的阻塞有何影响?

【问题讨论】:

  • 那里有问题吗?还是您只是提供状态报告?

标签: java multithreading


【解决方案1】:

问题是

data = pipeinputstream.read();

在线程 2 中是一个阻塞调用。来自PipedInputStream#read()的javadoc

此方法阻塞,直到输入数据可用,结束 检测到流,或者抛出异常。

线程 2 一直等到其中一件事情发生。由于它们都不会发生,线程将无法notify 另一个。

这不是死锁。

请注意,即使该调用未阻塞并返回 -1,线程 2 仍然可以在线程 1 调用 wait 之前执行其 notify。在这种情况下,线程 1 将处于持续等待状态,您的程序不会终止。

【讨论】:

  • 嗨,我将等待从 try 移到 finally 并且它有效。那么为什么等待会影响管道流呢?
  • 如果调用解除阻塞并返回 -1,线程 2 仍然可以在线程 1 调用等待之前执行其通知。在这种情况下,线程 1 将处于持续等待状态,您的程序不会终止。这是错误的,因为它会从 while 中出来并打印字符串缓冲区内容
  • @MacleanPinto wait 阻止线程 1 关闭流并解除线程 2 对 read 的调用。
  • @MacleanPinto 您无法控制线程调度程序。让我们采用您的新解决方案。如果线程调用close 并且有上下文切换,那么线程 2 现在将能够执行。假设它在另一个上下文切换之前执行包括notify 调用在内的所有内容,线程2 将通过调用wait 来恢复。然后notify它就什么都没有了。
猜你喜欢
  • 1970-01-01
  • 2017-10-30
  • 1970-01-01
  • 2018-12-05
  • 2013-07-22
  • 1970-01-01
  • 2012-01-27
  • 2011-07-17
  • 1970-01-01
相关资源
最近更新 更多