簡體   English   中英

Java線程並發

[英]Java thread concurrency

在下面的示例中,有人可以告訴我方法stampaVector()和stampaVector2()之間的區別嗎?

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

輸出執行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

輸出執行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

對於方法stampaVector2(),我希望獲得相同的stampaVector()輸出(當時只有一個線程訪問列表對象)。

謝謝

當你把synchronized的方法要同步在this 由於該類有兩個實例,每個實例都可以鎖定自身,因此兩者可以同時運行(無阻塞)。

synchronize this.list兩個實例都具有相同的list實例引用,因此它們都試圖獲得對單個對象的鎖定,因此是互斥的。

stampaVector正在同步您的列表。 多個線程無法在列表上執行同步代碼。

stampaVector2在它所在的ThreadConcurrance實例上同步。

其他線程只能在尚未同步的ThreadConcurrance實例上運行同步的代碼。

如果您希望類在其他地方同步,請使用stampaVector2的方法,並確保其他地方的代碼不會與stampaVector2同時運行。

使用這種方法的類我很少使用。 我更多地使用第一種方法。

第一個方法stampaVector()在執行內部代碼時同步list對象本身。 意味着執行該代碼段的第一個線程(在您的情況下為Thread-0 )獲取list的監視器。 因此,線程將鎖定該對象,並且在Thread-0釋放監視器之前,不允許其他線程執行該代碼段。 之后,第二個線程Thread-1獲取監視器並執行預期的方法。 當您使用相同的list引用初始化對象tc1和tc2時,監視器將鎖定完全相同的列表。

ThreadConcurrence tc1 = new ThreadConcurrence(list);
ThreadConcurrence tc2 = new ThreadConcurrence(list);

在第二種情況下, Thread-0獲取ThreadConcurrence對象的監視器,因此,當您執行stampaVector2()方法時,兩個線程都分別將監視器保留在tc1和tc2對象上,但不在列表本身上。 因此,該操作不同步。

例如,如果要初始化兩個不同的列表,則結果將相同:

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

在上述方法中,您正在同步list對象。 因此,在進入關鍵區域之前,請鎖定獲取的list對象的監視器。

public synchronized void stampaVector2(){
    for(Integer i:this.list){
        System.out.println("StampaVector2: "+Thread.currentThread().getName()+" "+i);
    }
}

在上面的方法中,在當前對象( this )上獲得了鎖定。 那就是tc1tc2

這種方法not thread safe因為兩個線程都在不同的監視器上獲取鎖。 這可能導致可能的race condition

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM