Yokupoku Maioku
Yokupoku Maioku

Reputation: 503

synchronize on multiple objects

In a previous question -> my question here i received a good solution (which works) to resolve my issue. But i haven't understand how exactly works.

So if i have many threads that can enter concurrently on this synchronized block, and according to the java docs this code is:

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

So, i' m asking:

why this operation is atomic:

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

and not this one:

       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");

my full function is this:

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");
        }
   }

Could someone provide me a useful explanation, i'll appreciate a lot.

Upvotes: 3

Views: 4213

Answers (2)

mavarazy
mavarazy

Reputation: 7735

As it's stated in comment, System.out.println is not thread safe operation.

The problem is the way you lock your critical section.

  synchronized (rows.get(row)) { }

This code means, that you are locking on specific row, not the whole table, so if you have N rows, that means N locks exist at the same time, and there fore N threads can run simultaneously populating System.out in parallel.

Locking on a row gives you a better parallelism: Thread working on row 2, can work at the same time, as Thread working on row 3.

Another option is to have a single lock for the whole table section.

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

In this case there is only one lock, and only one Thread executing it at the same time, so you are effectively calling your System.out synchronously from your code.

Locking on a table, decreases parallelism, since you decrease number of locks, available: Thread working on row 2, would need to wait for Thread working on row 3, to release the lock.

Thread safety, that synchronous guaranties affects only functions, written in the block, not externally called functions, it does not make System.out atomic operation.

Upvotes: 2

huidube
huidube

Reputation: 420

why dont you use your class object: synchronized(this)
or, even more secure: synchronized(YourClassName.class) or some other lock?

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

Every Java object created, including every Class loaded, has an associated lock or monitor. Putting code inside a synchronized block makes the compiler append instructions to acquire the lock on the specified object before executing the code, and release it afterwards (either because the code finishes normally or abnormally). Between acquiring the lock and releasing it, a thread is said to "own" the lock. At the point of Thread A wanting to acquire the lock, if Thread B already owns the it, then Thread A must wait for Thread B to release it.
(http://www.javamex.com/tutorials/synchronization_concurrency_synchronized1.shtml)

but if your lock changes, while a thread uses this lock in a synchronized block, it can occure that another block can enter the synchronized block with this changed lock. Example:

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

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

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

timeline:

thread1:
calling printValue() //taking the lock
thread2:
lock = new Object(); //the lock changes, its another object now
calling increment() //taking this new lock. the old lock is still reserved by thread1
value is getting incrementing.
threat1:
printing the wrong value.

EDIT: Didn't see that he needs a lock for each row.

Upvotes: 2

Related Questions