can someone tell me the difference between the method stampaVector() and stampaVector2() in the following example?
public class ThreadConcurrence implements Runnable{
ArrayList<Integer> list=null;
public ThreadConcurrence(ArrayList<Integer> list){
this.list = list;
}
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
for(int i=0; i<5; i++){
list.add(i);
}
//Threads shares same list object
ThreadConcurrence tc1 = new ThreadConcurrence(list);
ThreadConcurrence tc2 = new ThreadConcurrence(list);
Thread t1 = new Thread(tc1);
Thread t2 = new Thread(tc2);
t1.start();
t2.start();
}
@Override
public void run() {
stampaVector();
//stampaVector2();
}
public void stampaVector(){
synchronized(this.list){
for(Integer i:this.list){
System.out.println("StampaVector: "+Thread.currentThread().getName()+" "+i);
}
}
}
public synchronized void stampaVector2(){
for(Integer i:this.list){
System.out.println("StampaVector2: "+Thread.currentThread().getName()+" "+i);
}
}
}
Output executing stampaVector():
StampaVector: Thread-0 0
StampaVector: Thread-0 1
StampaVector: Thread-0 2
StampaVector: Thread-0 3
StampaVector: Thread-0 4
StampaVector: Thread-1 0
StampaVector: Thread-1 1
StampaVector: Thread-1 2
StampaVector: Thread-1 3
StampaVector: Thread-1 4
Output executing stampaVector2():
StampaVector2: Thread-0 0
StampaVector2: Thread-1 0
StampaVector2: Thread-1 1
StampaVector2: Thread-1 2
StampaVector2: Thread-0 1
StampaVector2: Thread-1 3
StampaVector2: Thread-1 4
StampaVector2: Thread-0 2
StampaVector2: Thread-0 3
StampaVector2: Thread-0 4
I would have expected the same output of stampaVector() (only one thread access the list object at time), for the method stampaVector2().
Thanks
when you put synchronized
on a method you are synchronizing on this
. Since there are two instances of the class each is able to get the lock on itself and therefore both run concurrently (no blocking).
In the synchronize this.list
both the instances have the same list
instance reference, therefore they are both trying to get the lock on a single object and are therefore mutually exclusive.
Part of stampaVector
is synchronizing on your list. More than one thread cannot execute code synchronizing on your list.
stampaVector2
is synchronized on the ThreadConcurrance
instance it exists within.
Other threads can only run code synchronized on your instance of ThreadConcurrance
if its not already synchronized.
Use the approach in stampaVector2
if you want the class to be synchronized on elsewhere, and ensure that code elsewhere is not running at the same time as stampaVector2
.
I don't often have a use for classes using that approach. More often I use the first approach.
The first method stampaVector()
synchronizes the list
object itself while the internal code is executed. meaning the first thread that executes that piece of code (in your case the Thread-0
) acquires the monitor of the list
. Therefore the thread locks that object and no other thread is allowed to execute that piece of code until the Thread-0
releases the monitor. After that the second thread Thread-1
acquires the monitor and executes the intended method. And as you initialize both objects tc1 and tc2 with the same list
reference the monitor locks the exact very same list.
ThreadConcurrence tc1 = new ThreadConcurrence(list);
ThreadConcurrence tc2 = new ThreadConcurrence(list);
On the second case the Thread-0
acquires the monitor of the ThreadConcurrence
object therefore when you execute stampaVector2()
method both threads hold a monitor to the tc1 and tc2 objects respectively but not on the list itself. Therefore that operation is not synchronized.
In case for example you would initialize two distinct lists you would have the same result:
ArrayList<Integer> list1 = new ArrayList<Integer>();
ArrayList<Integer> list2 = new ArrayList<Integer>();
ThreadConcurrence tc1 = new ThreadConcurrence(list1);
ThreadConcurrence tc2 = new ThreadConcurrence(list2);
public void stampaVector(){
synchronized(this.list){
for(Integer i:this.list){
System.out.println("StampaVector: "+Thread.currentThread().getName()+" "+i);
}
}
}
In above method you are synchronizing over list
object. So lock monitor for list
object in acquired prior to entering the critical region.
public synchronized void stampaVector2(){
for(Integer i:this.list){
System.out.println("StampaVector2: "+Thread.currentThread().getName()+" "+i);
}
}
In above method lock is obtained on the current object( this
). That is tc1
and tc2
.
This approach is not thread safe
as both threads are acquiring lock on different monitors. This may led to possible race condition
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.