Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.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 调用两个同步方法时发生死锁 类下载程序扩展线程{ 私有输入流; 私有输出流输出; 私有ArrayList侦听器; 公共下载程序(URL、字符串outputFilename)引发IOException{ in=url.openConnection().getInputStream(); out=新文件OutputStream(outputFilename); 侦听器=新的ArrayList(); } 公共同步的void addListener(ProgressListener侦听器){ 添加(侦听器); } 公共同步的void RemovelListener(ProgressListener侦听器){ 删除(侦听器); } 私有同步的void updateProgress(int n){ for(ProgressListener:侦听器) onProgress(n); } 公开募捐{ int n=0,总计=0; 字节[]缓冲区=新字节[1024]; 试一试{ 而((n=in.read(buffer))!=-1){ out.write(缓冲区,0,n); 总+=n; updateProgress(总计); } out.flush(); }捕获(IOE){} } }_Java_Multithreading_Concurrency_Java.util.concurrent_Dining Philosopher - Fatal编程技术网

Java 调用两个同步方法时发生死锁 类下载程序扩展线程{ 私有输入流; 私有输出流输出; 私有ArrayList侦听器; 公共下载程序(URL、字符串outputFilename)引发IOException{ in=url.openConnection().getInputStream(); out=新文件OutputStream(outputFilename); 侦听器=新的ArrayList(); } 公共同步的void addListener(ProgressListener侦听器){ 添加(侦听器); } 公共同步的void RemovelListener(ProgressListener侦听器){ 删除(侦听器); } 私有同步的void updateProgress(int n){ for(ProgressListener:侦听器) onProgress(n); } 公开募捐{ int n=0,总计=0; 字节[]缓冲区=新字节[1024]; 试一试{ 而((n=in.read(buffer))!=-1){ out.write(缓冲区,0,n); 总+=n; updateProgress(总计); } out.flush(); }捕获(IOE){} } }

Java 调用两个同步方法时发生死锁 类下载程序扩展线程{ 私有输入流; 私有输出流输出; 私有ArrayList侦听器; 公共下载程序(URL、字符串outputFilename)引发IOException{ in=url.openConnection().getInputStream(); out=新文件OutputStream(outputFilename); 侦听器=新的ArrayList(); } 公共同步的void addListener(ProgressListener侦听器){ 添加(侦听器); } 公共同步的void RemovelListener(ProgressListener侦听器){ 删除(侦听器); } 私有同步的void updateProgress(int n){ for(ProgressListener:侦听器) onProgress(n); } 公开募捐{ int n=0,总计=0; 字节[]缓冲区=新字节[1024]; 试一试{ 而((n=in.read(buffer))!=-1){ out.write(缓冲区,0,n); 总+=n; updateProgress(总计); } out.flush(); }捕获(IOE){} } },java,multithreading,concurrency,java.util.concurrent,dining-philosopher,Java,Multithreading,Concurrency,Java.util.concurrent,Dining Philosopher,以上代码摘自《七周七个并发模型》一书。这本书说,上面的代码有可能出现死锁,因为同步方法updateProgress调用可能获得另一个锁的外来方法[onProgress]。 由于我们在没有正确顺序的情况下获取了两个锁,因此可能会发生死锁 有人能解释一下在上述场景中死锁是如何发生的吗 提前感谢。以下示例导致死锁,因为MyProgressListener试图获取下载程序锁,而它已经被获取 class Downloader extends Thread { private InputStream

以上代码摘自《七周七个并发模型》一书。这本书说,上面的代码有可能出现死锁,因为同步方法updateProgress调用可能获得另一个锁的外来方法[onProgress]。 由于我们在没有正确顺序的情况下获取了两个锁,因此可能会发生死锁

有人能解释一下在上述场景中死锁是如何发生的吗


提前感谢。

以下示例导致死锁,因为MyProgressListener试图获取下载程序锁,而它已经被获取

class Downloader extends Thread {
    private InputStream in;
    private OutputStream out;
    private ArrayList<ProgressListener> listeners;
    public Downloader(URL url, String outputFilename) throws IOException {
        in = url.openConnection().getInputStream();
        out = new FileOutputStream(outputFilename);
        listeners = new ArrayList<ProgressListener>();
    }
    public synchronized void addListener(ProgressListener listener) {
        listeners.add(listener);
    }
    public synchronized void removeListener(ProgressListener listener) {
        listeners.remove(listener);
    }

    private synchronized void updateProgress(int n) {
        for (ProgressListener listener: listeners)
            listener.onProgress(n);
    }
    public void run() {
        int n = 0, total = 0;
        byte[] buffer = new byte[1024];
        try {
            while((n = in.read(buffer)) != -1) {
                out.write(buffer, 0, n);
                total += n;
                updateProgress(total);
            }
            out.flush();
        } catch (IOException e) { }
    }
}

下面的示例导致死锁,因为MyProgressListener试图获取下载程序锁,而它已经被获取

class Downloader extends Thread {
    private InputStream in;
    private OutputStream out;
    private ArrayList<ProgressListener> listeners;
    public Downloader(URL url, String outputFilename) throws IOException {
        in = url.openConnection().getInputStream();
        out = new FileOutputStream(outputFilename);
        listeners = new ArrayList<ProgressListener>();
    }
    public synchronized void addListener(ProgressListener listener) {
        listeners.add(listener);
    }
    public synchronized void removeListener(ProgressListener listener) {
        listeners.remove(listener);
    }

    private synchronized void updateProgress(int n) {
        for (ProgressListener listener: listeners)
            listener.onProgress(n);
    }
    public void run() {
        int n = 0, total = 0;
        byte[] buffer = new byte[1024];
        try {
            while((n = in.read(buffer)) != -1) {
                out.write(buffer, 0, n);
                total += n;
                updateProgress(total);
            }
            out.flush();
        } catch (IOException e) { }
    }
}

可能是这段代码中的问题:

class MyProgressListener extends ProgressListener {
    private Downloader myDownloader;

    public MyProgressListener(Downloader downloader) {
        myDownloader = downloader;
    }

    public void onProgress(int n) {
        // starts and waits for a thread that accesses myDownloader
    }
}

Downloader downloader = new Downloader(...);
downloader.addListener(new MyListener(downloader));
downloader.run();
当一个持有锁的线程调用外部方法时 像这个(onProgress),你不能保证 此方法的实现不会尝试获取其他锁,
可以用不同的线来固定。这可能会导致死锁。

可能是此代码中的问题:

class MyProgressListener extends ProgressListener {
    private Downloader myDownloader;

    public MyProgressListener(Downloader downloader) {
        myDownloader = downloader;
    }

    public void onProgress(int n) {
        // starts and waits for a thread that accesses myDownloader
    }
}

Downloader downloader = new Downloader(...);
downloader.addListener(new MyListener(downloader));
downloader.run();
当一个持有锁的线程调用外部方法时 像这个(onProgress),你不能保证 此方法的实现不会尝试获取其他锁,
可以用不同的线来固定。这可能会导致死锁。

首先,回想一下,将关键字
synchronized
应用于类时,意味着锁定此方法所属的整个对象。现在,让我们画出另两个触发死锁的对象:

for (ProgressListener listener: listeners)
            listener.onProgress(n);
class DLlistener implements ProgressListener {

  private Downloader d;

  public DLlistener(Downloader d){
      this.d = d;
      // here we innocently register ourself to the downloader: this method is synchronized
      d.addListener(this);
  }

  public void onProgress(int n){
    // this method is invoked from a synchronized call in Downloader
    // all we have to do to create a dead lock is to call another synchronized method of that same object from a different thread *while holding the lock*
    DLthread thread = new DLThread(d);
    thread.start();
    thread.join();
  }
}

// this is the other thread which will produce the deadlock
class DLThread extends Thread {
   Downloader locked;
  DLThread(Downloader d){
    locked = d;
  }
  public void run(){
    // here we create a new listener, which will register itself and generate the dead lock
    DLlistener listener(locked);
    // ...
  }
}

避免死锁的一种方法是通过让内部侦听器队列等待添加/删除来推迟在
addListener
中完成的工作,并让
Downloader
自己定期处理这些侦听器。这最终取决于下载程序。当然要运行内部工作。

首先,回想一下关键字
synchronized
,当应用于类时,意味着锁定此方法所属的整个对象。现在,让我们画出另两个触发死锁的对象:

for (ProgressListener listener: listeners)
            listener.onProgress(n);
class DLlistener implements ProgressListener {

  private Downloader d;

  public DLlistener(Downloader d){
      this.d = d;
      // here we innocently register ourself to the downloader: this method is synchronized
      d.addListener(this);
  }

  public void onProgress(int n){
    // this method is invoked from a synchronized call in Downloader
    // all we have to do to create a dead lock is to call another synchronized method of that same object from a different thread *while holding the lock*
    DLthread thread = new DLThread(d);
    thread.start();
    thread.join();
  }
}

// this is the other thread which will produce the deadlock
class DLThread extends Thread {
   Downloader locked;
  DLThread(Downloader d){
    locked = d;
  }
  public void run(){
    // here we create a new listener, which will register itself and generate the dead lock
    DLlistener listener(locked);
    // ...
  }
}

避免死锁的一种方法是通过让内部侦听器队列等待添加/删除来推迟在
addListener
中完成的工作,并让
Downloader
自己定期处理这些侦听器。这最终取决于
下载程序。当然,运行
内部工作。

最好将与
同步的
对象设置为私有对象

由于您在
下载程序
上同步,因此不知道其他线程是否也在
下载程序
上同步

以下侦听器导致死锁:

for (ProgressListener listener: listeners)
            listener.onProgress(n);
class DLlistener implements ProgressListener {

  private Downloader d;

  public DLlistener(Downloader d){
      this.d = d;
      // here we innocently register ourself to the downloader: this method is synchronized
      d.addListener(this);
  }

  public void onProgress(int n){
    // this method is invoked from a synchronized call in Downloader
    // all we have to do to create a dead lock is to call another synchronized method of that same object from a different thread *while holding the lock*
    DLthread thread = new DLThread(d);
    thread.start();
    thread.join();
  }
}

// this is the other thread which will produce the deadlock
class DLThread extends Thread {
   Downloader locked;
  DLThread(Downloader d){
    locked = d;
  }
  public void run(){
    // here we create a new listener, which will register itself and generate the dead lock
    DLlistener listener(locked);
    // ...
  }
}
导致死锁的代码: 如果运行该代码,将发生以下情况:

  • 主线程到达
    updateProgress
    并在
    下载程序上获得锁
  • 调用
    MyProgressListener
    onProgress
    方法,并启动新线程
    t
  • 主线程到达
    t.join()

  • 在这种情况下,主线程在
    t
    完成之前无法继续,但要完成
    t
    ,主线程必须释放其在
    下载程序上的锁,但这不会发生,因为主线程无法处理->死锁最好将与
    同步的对象设置为私有对象

    由于您在
    下载程序
    上同步,因此不知道其他线程是否也在
    下载程序
    上同步

    以下侦听器导致死锁:

    for (ProgressListener listener: listeners)
                listener.onProgress(n);
    
    class DLlistener implements ProgressListener {
    
      private Downloader d;
    
      public DLlistener(Downloader d){
          this.d = d;
          // here we innocently register ourself to the downloader: this method is synchronized
          d.addListener(this);
      }
    
      public void onProgress(int n){
        // this method is invoked from a synchronized call in Downloader
        // all we have to do to create a dead lock is to call another synchronized method of that same object from a different thread *while holding the lock*
        DLthread thread = new DLThread(d);
        thread.start();
        thread.join();
      }
    }
    
    // this is the other thread which will produce the deadlock
    class DLThread extends Thread {
       Downloader locked;
      DLThread(Downloader d){
        locked = d;
      }
      public void run(){
        // here we create a new listener, which will register itself and generate the dead lock
        DLlistener listener(locked);
        // ...
      }
    }
    
    导致死锁的代码: 如果运行该代码,将发生以下情况:

  • 主线程到达
    updateProgress
    并在
    下载程序上获得锁
  • 调用
    MyProgressListener
    onProgress
    方法,并启动新线程
    t
  • 主线程到达
    t.join()

  • 在这种情况下,主线程在
    t
    完成之前无法继续,但要完成
    t
    ,主线程必须释放其在
    下载程序上的锁,但这不会发生,因为主线程无法处理->死锁

    下面是一个经典示例,它显示了作者试图避免的那种难以调试的问题

    创建类
    UseDownloader
    ,并调用
    downloadSomething

    随着下载的进行,调用
    onProgress
    方法。由于这是从同步块内调用的,
    下载程序
    motinor被锁定。在我们的
    onProgress
    方法中,我们需要锁定自己的资源,在本例中是
    lock
    。因此,当我们尝试在
    lock