Java:如何同步数组访问以及对同步条件中的内容有何限制

时间:2011-09-08 16:01:29

标签: java synchronization

我有一个2x2阵列,我有两个线程在运行。

可以在数组的java中使用synchronized语句吗?

锁定如何工作? java教程线程说同步语句适用于对象,所以我不确定它们是什么意思。另一个网站说我可以发表一个声明,如

synchronized (array1[]){

}

这是否同步访问数组中的所有内容,以便将数组锁定到其他线程?

如果我有一个二维数组,我可以使用

synchronized (array1[i])锁定数组中的一行?

是否可以锁定单个数组值 像

这样的东西
synchronized (array1[i][j]){

}

但是,非常感谢提示或帮助。实际上我已经把它打开了,无论是否正确。但我想知道将来使用

4 个答案:

答案 0 :(得分:12)

是的,您可以使用数组作为监视对象进行同步,因为数组(甚至是基元数组)是Java中的对象。

您可以在特定监视器上同步代码块,如下所示:

public void myMethod() {

    unsynchronized_statements...

    synchronized(myMonitorObject) {
        synchronized_statments...
    }

最佳做法是尽可能少地同步代码。

同步监视器上的代码不会以任何方式影响监视器,它只影响访问同步代码块的线程。在线程执行可以进入代码块之前,它必须在监视器上获得“锁定”。 Java运行时确保一次最多一个线程可以在监视器上具有“锁定”。 因此,对阵列进行同步并不会禁止不同步的代码块来访问它!诀窍是确保您不希望同时发生的所有操作都在同步的块内。同一台监视器。

由于Java不提供多维数组,只提供数组数组,因此您可以在嵌套数组上进行同步,以实现更细粒度的同步。如果将2d数组建模为行数组,则只能在行上而不是在列上进行同步,因为在该示例中,列不表示为单独的数组。

如果这些值不是原始值,则只能对单个数组值进行同步,因此Integer()而不是int。请注意,Integer()是一个不可变对象,因此您无法更改其值。一个解决方案是使用getter和setter为包含的数值创建自己的Cell()包装器对象。这将允许您让一个线程获取Cell上的锁并安全地更改其值。

因为这是我的休息日,所以我决定玩得开心,并创建了一个你所描述的实例。是的,这是我开心的想法。

类:

应用程序在同一矩阵上启动多个操作。唯一的同步代码块在类Operation中。如果删除同步,结果将是错误的,因为两个操作同时操作同一行。

同步时输出:

[105, 104, 103, 102, 101]
[110, 109, 108, 107, 106]
[115, 114, 113, 112, 111]
[120, 119, 118, 117, 116]
[125, 124, 123, 122, 121]
[130, 129, 128, 127, 126]
[135, 134, 133, 132, 131]
[140, 139, 138, 137, 136]
[145, 144, 143, 142, 141]
[150, 149, 148, 147, 146]

NOT synchronized时的输出示例:

[105, 4, 103, 102, 101]
[110, 9, 108, 207, 106]
[115, 14, 113, 212, 111]
[120, 19, 118, 217, 116]
[125, 124, 123, 122, 121]
[130, 129, 128, 127, 126]
[135, 34, 133, 232, 131]
[140, 139, 138, 137, 136]
[145, 144, 143, 142, 141]
[150, 149, 148, 147, 146]

请注意,我在操作实现中添加了一些Thread.sleep()语句,以使同步和非同步执行之间的区别更加明显。

答案 1 :(得分:3)

不,以这种方式同步只意味着您锁定了数组对象,而不是实际上是在同步对其方法的访问。如果您的阵列对其他人可见,他们仍可以访问/修改其内容,无论其是否被锁定。只有他们不能同时锁定它 - 如果他们尝试(来自不同的线程),他们将被阻止,直到其原始收单机构释放锁。

如果要确保一次只有一个线程正在访问数组(或其中一个元素),则需要将其封装在类中并同步操作数组的所有公共类方法。 (您可以为此目的锁定数组,但是,如果您愿意 - 更简单和通常的方法是将方法本身声明为synchronized,在这种情况下,它们的内容在this上同步,封闭的对象)。

class ArrayWrapper {
  private int[] array = ...;

  public void setValue(int index, int value) {
    synchronized (array) {
      array[index] = value;
    }
  }

  public int getValue(int index) {
    synchronized (array) {
      return array[index];
    }
  }

  ...
}

答案 2 :(得分:3)

synchronized关键字仅适用于对象。

同步数组只锁定数组(在Java中,数组是一个对象)。

如果你在某个数组中单独元素同步,请求它们是对象而不是基元,这是另一个不同的锁。你可以拥有一个没有另一个,反之亦然。您无法在基元上进行同步。

如果您需要阻止对阵列的并发修改,请在每次对阵列的访问中同步某个对象。您可以为此目的使用您想要的任何对象,但它必须与工作相同。请注意,如果您使用同步访问共享资源,并且访问的代码的其他部分没有同步或同步其他对象,那么这对任何事都没有用。

答案 3 :(得分:1)

同步对象或数组时,阻止另一个线程同步而不是同一个对象。这不会阻止您使用该对象,并且没有其他操作被“锁定”您必须确保首先以一致的方式锁定该对象,以便“锁定”该对象。