同步多个对象

时间:2014-10-22 07:45:48

标签: java multithreading

在上一个问题中 - > my question here我收到了一个很好的解决方案(有效)来解决我的问题。 但我无法理解究竟是如何运作的。

因此,如果我有许多线程可以在此同步块上并发输入,并且根据java文档,此代码为:

synchronized(...){
   //atomic for the operation inside 
}

所以,我'问:

为什么这个操作是原子的:

for (int j = 0; j < column; j++) {
                    matrix[row][j] += 1;
                }

而不是这一个:

       System.out.println("begin print");
         for (int i = 0; i < this.row; i++) {
             System.out.println();
             for (int j = 0; j < column; j++)
                 System.out.print(matrix[i][j]);
          }
        System.out.println();
        System.out.println("end print");

我的全部功能是:

public  void increaseRow(Integer row) {
        synchronized (rows.get(row)) {
            for (int j = 0; j < column; j++) {
                matrix[row][j] += 1;
            }
            System.out.println("begin print");
            for (int i = 0; i < this.row; i++) {
                System.out.println();
                for (int j = 0; j < column; j++)
                    System.out.print(matrix[i][j]);
            }
            System.out.println();
            System.out.println("end print");
        }
   }

有人能给我一个有用的解释,我会非常感激。

2 个答案:

答案 0 :(得分:2)

为什么不使用你的类对象:synchronized(this)
或者,更安全:synchronized(YourClassName.class) 或其他一些锁?

Object lock = new Object();
...
public void someMethod(){
    synchronized(lock){...}
}
  

创建的每个Java对象(包括每个加载的类)都有一个关联的锁或监视器。将代码放在synchronized块中会使编译器附加指令以在执行代码之前获取指定对象的锁定,然后释放它(因为代码正常或异常完成)。在获取锁定并释放它之间,一个线程被称为“拥有”和“#34;锁。在线程A想要获取锁定时,如果线程B已经拥有它,则线程A必须等待线程B释放它。
  (http://www.javamex.com/tutorials/synchronization_concurrency_synchronized1.shtml

但是如果您的锁更改,而线程在同步块中使用此锁,则可能会发生另一个块可以使用此更改的锁进入同步块。 例如:

Object lock = new Object();
int value = 0;

public void increment(){
    synchronized(lock){value++;}
}

public void printValue(){
    synchronized(lock){System.out.println(value);}
}

的时间表:

线程1:
调用printValue()//获取锁定 线程2:
lock = new Object(); //锁定发生变化,现在是另一个对象 调用increment()//获取此新锁。旧的锁仍然由thread1保留 价值正在增加 threat1:
打印错误的值。

编辑:没有看到他需要锁定每一行。

答案 1 :(得分:2)

正如评论中所述,System.out.println不是线程安全操作。

问题在于你锁定关键部分的方式。

  synchronized (rows.get(row)) { }

此代码表示您锁定特定行,而不是整个表,所以如果你有N行,那意味着N锁存在,那么前N个线程就可以了同时运行并行填充System.out。

锁定一行可以提供更好的并行性:第2行的线程可以同时工作,就像第3行的线程一样。

另一种选择是为整个表部分设置一个锁。

Object lock = new Object();
...
public void someMethod(){
    synchronized(lock){...}
}

在这种情况下,只有一个锁,并且只有一个Thread同时执行它,因此您可以从代码中同步调用System.out。

锁定表,减少并行性,因为减少了锁的数量,可用:在第2行上运行的线程需要等待第3行的Thread工作,才能释放锁。

线程安全,即同步保证仅影响函数,写入块,而不是外部调用函数,它不会使System.out原子操作。