简体   繁体   中英

Java thread concurrency

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM