简体   繁体   English

Java,具有同步方法的多线程

[英]Java, Multithreading with synchronized methods

I am having some trouble getting my program to not deadlock at times. 我有时无法使程序不陷入僵局。 I think I need to add a third synchronized method release, which can be used to release the other thread after a ping is called. 我想我需要添加第三个同步方法版本,可在调用ping后将其用于释放另一个线程。 code is below. 代码如下。

// Attempt at a simple handshake.  Girl pings Boy, gets confirmation.
// Then Boy pings girl, get confirmation.
class Monitor {
    String name;

    public Monitor (String name) { this.name = name; }

    public String getName() {  return this.name; }

     // Girl thread invokes ping, asks Boy to confirm.  But Boy invokes ping,
    // and asks Girl to confirm.  Neither Boy nor Girl can give time to their
    // confirm call because they are stuck in ping.  Hence the handshake 
    // cannot be completed.
    public synchronized void ping (Monitor p) {
      System.out.println(this.name + " (ping): pinging " + p.getName());
      p.confirm(this);
      System.out.println(this.name + " (ping): got confirmation");
    }

    public synchronized void confirm (Monitor p) {
       System.out.println(this.name+" (confirm): confirm to "+p.getName());
     }
}

class Runner extends Thread {
    Monitor m1, m2;

    public Runner (Monitor m1, Monitor m2) { 
      this.m1 = m1; 
      this.m2 = m2; 
    }

    public void run () {  m1.ping(m2);  }
}

public class DeadLock {
    public static void main (String args[]) {
      int i=1;
      System.out.println("Starting..."+(i++));
      Monitor a = new Monitor("Girl");
      Monitor b = new Monitor("Boy");
      (new Runner(a, b)).start();
      (new Runner(b, a)).start();
    }
}

When some operation needs to get hold of two different locks the only way of ensuring that there are no deadlocks is to make sure that every thread trying to perform those operations acquires the lock on the multiple objects in the same order. 当某些操作需要持有两个不同的锁时,确保没有死锁的唯一方法是确保每个尝试执行这些操作的线程都以相同的顺序获取多个对象的锁。

To fix deadlock you need to modify the code like this - not pretty, but it works. 要修复死锁,您需要像这样修改代码-不太漂亮,但是可以工作。

 public void ping (Monitor p) {
  Monitor one = this;
  Monitor two = p;
  // use some criteria to get a consistent order
  if (System.identityHashCode(one) > System.identityHashCode(two)) {
    //swap
    Monitor temp = one;
    one = two;
    two = one;
  }
  synchronized(one) {
       synchronized(two) {
           System.out.println(this.name + " (ping): pinging " + p.getName());
           p.confirm(this);
           System.out.println(this.name + " (ping): got confirmation");
        }
  }
}

This is tricky stuff. 这是棘手的东西。 I'd make Monitor.name volatile , or synchronize it with its own lock object. 我将Monitor.name设置为volatile ,或将其与自己的锁对象同步。 Or best yet: make it final . 还是最好的: final Then ditch the synchronized keyword from your two methods. 然后,从您的两个方法中删除synchronized关键字。 Other than "name", there's nothing in there that's not thread safe. 除了“名称”之外,这里没有线程安全的东西。

Otherwise, don't synchronize until you need to. 否则,直到需要时才进行同步。 Use synchronized blocks, not methods. 使用同步块,而不是方法。 Don't put anything into a synch block unless it needs to be there. 除非需要将任何内容放入同步块,否则不要将其放入其中。 Synch fields separately on separate lock objects if you can. 如果可以,请分别在单独的锁定对象上同步字段。 Don't nest synch blocks, but if you have to always nest them in the same sequence; 不要嵌套同步块,但是如果您必须始终按相同的顺序嵌套它们; have a hierarchy of synch objects. 具有同步对象的层次结构。

Synching all your methods is a simple, handly technique for staying thread safe. 同步所有方法是一种保持线程安全的简便方法。 However, it's easy to deadlock or just slow way down when your threads start interacting. 但是,当线程开始进行交互时,很容易造成死锁或缓慢下降。 Then it gets interesting. 然后变得有趣。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM