[英]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
)上獲得了鎖定。 那就是tc1
和tc2
。
這種方法not thread safe
因為兩個線程都在不同的監視器上獲取鎖。 這可能導致可能的race condition
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.