I would an explanation on these different implmentations:
First:
public void foo(Object key){
synchronized (map.get(key)) { //-> thread can enter with different key
int variable = 0;
for (int j = 0; j <new Random().nextInt(10); j++)
variable+=j;
return variable;
}
}
Second:
public void foo(Object key){
int variable = 0;
synchronized (map.get(key)) {
for (int j = 0; j < new Random().nextInt(10); j++)
variable+=j;
return variable;
}
}
Third:
public void foo(Object key){
int variable = 0;
synchronized (map.get(key)) {
for (int j = 0; j <new Random().nextInt(10); j++)
variable+=j;
lock.lock(); // class instance lock
try{
setTheVariable(variable) //-> Example.....
}finally{
lock.unlock();
}
return variable;
}
}
In my opinion the first two implementations are the same, if each thread enter the syncrhonized block they share the for loop but they have got their own variable copy, is right?
I have a doubt in the third implementation, if each thread enter the syncrhonzized block , after finishing only one can enter inside the lock block and the other have to wait. In this case when one thread can return each variable resulting of the for loop remains attached on his own thread?
thanks in advance.
Variables declared inside the foo() method remains attached to the individual threads,because they are local variables. Here you are declaring "j" and "variable" inside the method and those variables will remain attached to the thread executing the method.
Your first two implementations are the same.
In your third implementation, only one thread can enter the synchronized block, irrespective of whether it is an class instance variable, so the lock is somehow redundant unless your //Do Something Here section has a compelling reason to do so.
Because all the variables involved are local variables, each thread has its own copy of these variables. The returned value of one thread will not be affected by another thread.
However, always watch out for deadlock if two locks are used in this fashion.
Related
I have two threads to sell tickets.
public class MyThread {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread thread1 = new Thread(()->{
for (int i = 0; i < 30; i++) {
ticket.sell();
} }, "A");
thread1.start();
Thread thread2 = new Thread(()->{
for (int i = 0; i < 30; i++) {
ticket.sell();
} }, "B");
thread2.start();
}
}
class Ticket {
private Integer num = 20 ;
private Object obj = new Object();
public void sell() {
// why shouldn't I use "num" as a monitor object ?
// I thought "num" is unique among two threads.
synchronized ( num ) {
if (this.num >= 0) {
System.out.println(Thread.currentThread().getName() + " sells " + this.num + "th ticket");
this.num--;
}
}
}
}
The output will be wrong if I use num as a monitor object.
But if I use obj as a monitor object, the output will be correct.
What's the difference between using num and using obj ?
===============================================
And why does it still not work if I use (Object)num as a monitor object ?
class Ticket {
private int num = 20 ;
private Object obj = new Object();
public void sell() {
// Can I use (Object)num as a monitor object ?
synchronized ( (Object)num ) {
if (this.num >= 0) {
System.out.println(Thread.currentThread().getName() + " sells " + this.num + "th ticket");
this.num--;
}
}
}
}
Integer is a boxed value. It contains a primitive int, and the compiler deals with autoboxing/autounboxing that int. Because of this, the statement this.num-- is actually:
num=Integer.valueOf(num.intValue()-1)
That is, the num instance containing the lock is lost once you perform that update.
The fundamental problem here is synchronizing on a non-final value.
The most important thing to understand about the Java Memory Model - that is, what values a thread sees whilst executing a Java program - is the happens-before relationship.
In the specific case of a synchronized block, actions done in one thread before exiting the synchronized block happen before actions done inside the synchronized block in another thread - so, if the first thread increments a variable inside that synchronized block, the second thread sees that updated value.
This goes over and above the well-known fact that a synchronized block can only be entered by one thread at a time: only one thread at a time and you get to see what the previous thread did.
// Thread 1 // Thread 2
synchronized (monitor) {
num = 1
} // Exiting monitor
// *happens before*
// entering monitor
synchronized (monitor) {
int n = num; // Guaranteed to see n = 1 (provided no other thread has entered a block synchronized on monitor and changed it first).
}
There is a very important caveat to this guarantee: it only holds if the two executions of the synchronized block use the same monitor. And that's not the same variable, it's the same actual concrete object on the heap (variables don't have monitors, they're just pointers to a value in the heap).
So, if you reassign the monitor inside the synchronized block:
synchronized (num) {
if (num > 0) {
num--; // This is the same as `num = Integer.valueOf(num.intValue() - 1);`
}
}
then you are destroying the happens-before guarantee, because the next thread to arrive at that synchronized block is entering the monitor of a different object (*).
Once you do, the behavior of your program is ill-defined: if you're lucky, it fails in an obvious way; if you're very unlucky, it can seem to work, and then start failing mysteriously at a later date.
Your code is just broken.
This isn't something that's specific to Integers either: this code would have the same problem.
// Assume `Object someObject = new Object();` is defined as a field.
synchronized (someObject) {
someObject = new Object();
}
(*) Actually, you still get a happens-before relationship for the new object: it's just not for the things inside this synchronized block, it's for things that happened in some other synchronized block that used the object as the monitor. Essentially, it's impossible to reason about what this means, so you may as well just consider it "broken".
The correct way to do it is to synchronize on a field that you can't (not just don't) reassign. You could simply synchronize on this (which can't be reassigned):
synchronized (this) {
if (num > 0) {
num--; // This is the same as `num = Integer.valueOf(num.intValue() - 1);`
}
}
Now it doesn't matter that you're reassigning num inside the block, because you're not synchronizing on it any more. You get the happens-before guarantee from the fact that you're always synchronizing on the same thing.
Note, however, that you must always access num from inside a synchronized block - for example, if you have a getter to get the number of tickets remaining, that must also synchronize on this, in order to get the happens-before guarantee that the value changed in the sell() method is visible in that getter.
This works, but it may not be entirely desirable: anybody who has access to a reference to your Ticket instance can also synchronize on it. This means they can potentially deadlock your code.
Instead, it is a common practice to introduce a private field which is used purely for locking: this is what the obj field gives you. The only modification from your code should be to make it final (and give it a better name than obj):
private final Object obj = new Object();
This can't be accessed outside your class, so nefarious clients cannot cause a deadlock for you directly.
Again, this can't be reassigned inside your synchronized block (or anywhere else), so there is no risk of you breaking the happens-before guarantee by reassigning it.
I just came across the synchronized block in Java and wrote a small programm to test how it works.
I create 10 threads and let each thread increment an Integer object 1000 times.
So with synchronization I would assume a result of 10000 after all threads have finished their work and a result of less than 10000 without synchronization .
However the synchronization is not wokring as I expected.
I guess it has something to do with immutability of the object or so.
My program:
public class SyncTest extends Thread{
private static Integer syncObj = new Integer(0);
private static SyncTest[] threads = new SyncTest[10];
private boolean done = false;
public void run(){
for(int i = 0; i < 1000; i++){
synchronized(syncObj){
syncObj ++;
}
}
done = true;
}
public static void main(String[] args) {
for(int i=0; i < threads.length; i++){
threads[i] = new SyncTest();
threads[i].start();
}
while(!allDone()); //wait until all threads finished
System.out.println(syncObj);
}
private static boolean allDone(){
boolean done = true;
for(int i = 0; i < threads.length; i++){
done &= threads[i].done;
}
return done;
}
}
Can someone clarify this?
syncObject is changing each time you ++ it (the ++ is converting it to a primitive int, incrementing it, and then autoboxing it back to the Integer object. Integer objects are immutable ... once they are created, they cannot change.
Bottom ine is that you are not using the same syncPObj in all the threads, different threads use different syncObjects at different times to sync on.
use one object as the synchronization (call it syncObj), and declare it as a final Object:
private static final Object syncObject = new Object();
Then your counter should be a primitive (int) for perofrmance, call it 'counter' or something.
Synchronize on syncObject, and increment counter.
Edit: as per #jsn, the done flag is also broken in that your code has a 'tight loop' on the isAllDone() method, and that is bad practice. You should use thread[i].join() to wait (blocking) on each thread's completion, and then check the status from that. Using an ExecutorService is the 'right way'.
As assumed it is because of the immutability of the Integer object.
I've changed the synchonized block to
Integer old = syncObj;
syncObj ++;
System.out.println(syncObj == old);
and my console gets filled with falses
So each time I increment the Integer a new object is createt.
Therefore I only read from the old Object and it will not be locked.
These operations are usually done with Atomic. Have a look here. These structures are specifically designed for multi-threaded computation. Normal implementations are not thread safe.
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.
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.
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.
I just came across the synchronized block in Java and wrote a small programm to test how it works.
I create 10 threads and let each thread increment an Integer object 1000 times.
So with synchronization I would assume a result of 10000 after all threads have finished their work and a result of less than 10000 without synchronization .
However the synchronization is not wokring as I expected.
I guess it has something to do with immutability of the object or so.
My program:
public class SyncTest extends Thread{
private static Integer syncObj = new Integer(0);
private static SyncTest[] threads = new SyncTest[10];
private boolean done = false;
public void run(){
for(int i = 0; i < 1000; i++){
synchronized(syncObj){
syncObj ++;
}
}
done = true;
}
public static void main(String[] args) {
for(int i=0; i < threads.length; i++){
threads[i] = new SyncTest();
threads[i].start();
}
while(!allDone()); //wait until all threads finished
System.out.println(syncObj);
}
private static boolean allDone(){
boolean done = true;
for(int i = 0; i < threads.length; i++){
done &= threads[i].done;
}
return done;
}
}
Can someone clarify this?
syncObject is changing each time you ++ it (the ++ is converting it to a primitive int, incrementing it, and then autoboxing it back to the Integer object. Integer objects are immutable ... once they are created, they cannot change.
Bottom ine is that you are not using the same syncPObj in all the threads, different threads use different syncObjects at different times to sync on.
use one object as the synchronization (call it syncObj), and declare it as a final Object:
private static final Object syncObject = new Object();
Then your counter should be a primitive (int) for perofrmance, call it 'counter' or something.
Synchronize on syncObject, and increment counter.
Edit: as per #jsn, the done flag is also broken in that your code has a 'tight loop' on the isAllDone() method, and that is bad practice. You should use thread[i].join() to wait (blocking) on each thread's completion, and then check the status from that. Using an ExecutorService is the 'right way'.
As assumed it is because of the immutability of the Integer object.
I've changed the synchonized block to
Integer old = syncObj;
syncObj ++;
System.out.println(syncObj == old);
and my console gets filled with falses
So each time I increment the Integer a new object is createt.
Therefore I only read from the old Object and it will not be locked.
These operations are usually done with Atomic. Have a look here. These structures are specifically designed for multi-threaded computation. Normal implementations are not thread safe.
public class MyThread
{
volatile static int i;
public static class myT extends Thread
{
public void run ()
{
int j = 0;
while(j<1000000){
i++;
j++;
}
}
}
public static void main (String[] argv)
throws InterruptedException{
i = 0;
Thread my1 = new myT();
Thread my2 = new myT();
my1.start();
my2.start();
my1.join();
my2.join();
System.out.println("i = "+i);
}
}
Since volatile builds happens-before relationship, the final value of i should be strictly 2000000. However, the actual result is nothing different from being without volatile for variable i. Can anyone explanation why it doesn't work here? Since i is declared volatile, it should be protected from memory inconsistency.
Can anyone explanation why it doesn't work here? Since i is declared volatile, it should be protected from memory inconsistency.
It is protected but unfortunately i++ is not an atomic operation. It is actually read/increment/store. So volatile is not going to save you from the race conditions between threads. You might get the following order of operations from your program:
thread #1 reads i, gets 10
right afterwards, thread #2 reads i, gets 10
thread #1 increments i to 11
thread #2 increments i to 11
thread #1 stores 11 to i
thread #2 stores 11 to i
As you can see, even though 2 increments have happened and the value has been properly synchronized between threads, the race condition means the value only went up by 1. See this nice looking explanation. Here's another good answer: Is a volatile int in Java thread-safe?
What you should be using are AtomicInteger which allows you to safely increment from multiple threads.
static final AtomicInteger i = new AtomicInteger(0);
...
for (int j = 0; j<1000000; j++) {
i.incrementAndGet();
}