在编写Java类时,我偶然发现了一个烦恼。我不知道如何使复制二维数组线程安全。这是该类的简单版本:

public class Frame {
  private boolean[][] content;

  public Frame(boolean [][] content) {
    boolean[][] threadSafeCopy = deepCopy(content);
    if (!(threadSafeCopy != null)) {
      throw new NullPointerException("content must not be null");
    }
    if (!(threadSafeCopy.length > 0)) {
      throw new IllegalArgumentException("content.length must be greater than 0");
    }
    if (!(threadSafeCopy[0] != null)) {
      throw new IllegalArgumentException("content[0] must not be null");
    }
    if (!(threadSafeCopy[0].length > 0)) {
      throw new IllegalArgumentException("content[0].length must be greater than 0");
    }
    for (int i = 1, count = threadSafeCopy.length; i < count; ++i) {
      if (!(threadSafeCopy[i].length == threadSafeCopy[0].length)) {
        throw new IllegalArgumentException
            (   "content[" + i + "].length [" + threadSafeCopy[i].length
              + "] must be equal to content[0].length [" + threadSafeCopy[0].length + "]"
            );
      }
    }
    this.content = threadSafeCopy;
  }

  private boolean[][] deepCopy(boolean[][] content) {
    boolean[][] result = null;
    if (content != null) {
      synchronized(content) { //do our best to make this as multi-threaded friendly as possible
        result = new boolean[content.length][];
        for (int i = 0, count = content.length; i < count; ++ i) {
          if (content[i] != null)
          {
            synchronized(content[i]) {
              result[i] = content[i].clone();
            }
          }
        }
      }
    }
    return result;
  }

  public boolean[][] getContent() {
    boolean[][] result = new boolean[this.content.length][]; //defensive copy
    for (int i = 0, count = result.length; i < count; ++i) {
      result[i] = this.content[i].clone(); //defensive copy
    }
    return result;
  }
}


但是,上述方法private boolean[][] deepCopy(boolean[][] content)的实现实际上不是线程安全的。在此方法尝试复制时,该数组可能正在被另一个线程主动修改。的确,我在基本数组上使用synchronized来防止最恶劣的情况。但是,这不会导致第二维数组实例集被锁定。并且有可能在复制期间对其进行修改。

是否有某种方法可以为基本数组(content)和子数组(content[0]content[1],...,content[content.length - 1])中的每一个收集对象锁,这样我可以调用类似synchronized(objectsToLockSimultaneouslyList)并同时按列表顺序锁定所有对象。如果是这样,我可以安全地线程复制数组的内容。

如果没有,那么可以使用什么其他类型的解决方案来“阻止对数组的所有修改”,而不必去更改实例化Frame的类或更改Frame的构造函数,从而使其不采用数组,而只采用不可变集合的实例(它本身在另一个freakin兔子洞中)。

感谢您在此方面的任何指导。

更新:
我想做的事情根本不可能。我对通过同步锁定对象的理解也很错误(tyvm glowcoder,Paulo和Brian)。现在,我将尝试更改Frame的接口以使用List<List<Boolean>>,这似乎效率会低得多。或者我可以使用Set<XyCoordinate>,其中XyCoordinate的存在表示“ true”。再次,这似乎是如此低效,但线程安全。啊!

最佳答案

我认为您最好的选择是将数组包装在一个对象中并提供对其的同步访问。然后,您可以对访问器方法进行“门关闭”来进行深层复制。

void deepCopy(boolean[][] orig) {
    synchronized(orig) {
        boolean[][] result = new boolean[orig.length][];
        deepCopy(orig,0);
        return result;
    }
}

/**
 * recursive method to lock all rows in an array, and then copy
 * them in (backwards, by chance)
 */
void deepCopy(boolean[][] orig, int row) {
    if(row == orig.length) return; // end condition
    synchronized(orig[row]) { // lock the row first
        deepCopy(orig,row+1); // lock the next row
        content[row] = new boolean[orig[row].length];
        for(int i = 0; i < content[row].length; i++)
            content[row][i] = orig[row][i];
        // now, do row - 1
    }
}

08-08 05:59
查看更多