2017-02-15 211 views
0

我想了解java中的同步。我有下面的例子中, for循環同步方法

public class TestThr implements Runnable { 

    public static void main(String[] args) { 

      Thread t=new Thread(new TestThr()); 
      Thread t1=new Thread(new TestThr()); 

      t.start(); 
      t1.start(); 
    } 

    @Override 
    public void run() { 
     sync(); 
    } 

    public synchronized void sync(){ 
     for (int i=0;i<10;i++){ 
      System.out.println("Running "+Thread.currentThread().getName()); 
     } 
    } 

} 
 
Output : 
Running Thread-0 
Running Thread-1 
Running Thread-0 
Running Thread-1 
Running Thread-0 
Running Thread-1 
Running Thread-1 
Running Thread-1 
Running Thread-0 
Running Thread-1 
Running Thread-1 
Running Thread-1 
Running Thread-1 
Running Thread-1 
Running Thread-0 
Running Thread-0 
Running Thread-0 
Running Thread-0 
Running Thread-0 
Running Thread-0 

從上面的例子,我期待一個線程(誰進入第一)將完成迭代,然後第二次將啓動並完成,但我得到不一致的輸出。

請加你的意見。

在此先感謝。

+0

你搜索*堆棧溢出*爲的是什麼意思,同步的方法說明? – CKing

+0

@CKing抱歉,但我無法理解同步方法的行爲。爲了澄清同樣的問題。 – dullpointer

回答

3

這就是:

public synchronized void sync(){ 
    for (int i=0;i<10;i++){ 
     System.out.println("Running "+Thread.currentThread().getName()); 
    } 
} 

是這樣工作的:

public void sync(){ 
     synchronize(this) { 
      for (int i=0;i<10;i++){ 
       System.out.println("Running "+Thread.currentThread().getName()); 
      } 
     } 
    } 

所以,在你的情況下,每個線程同步通過不同TestThr對象:

要看到預期的輸出,你可以下一個試試:

public class TestThr implements Runnable { 
    static SeparatedClass monitor; 

    public static void main(String[] args) { 
     monitor = new SeparatedClass(); 

     Thread t=new Thread(new TestThr()); 
     Thread t1=new Thread(new TestThr()); 

     t.start(); 
     t1.start(); 
    } 

    @Override 
    public void run() { 
     monitor.sync(); 
    } 
} 

class SeparatedClass { 
    public synchronized void sync(){ 
     for (int i=0;i<10;i++){ 
      System.out.println("Running "+Thread.currentThread().getName()); 
     } 
    } 
} 
+0

@DullPointer這就是在這個答案中正在解釋的內容。您正在鎖定*此*。我假設你明白* this *指向什麼? – CKing

+0

'this'不指向't'和't1' @Pavlo。它指向'TestThr'的兩個實例。 – Gray

+0

對!我犯了一個錯誤。 –

3

從上面的例子我期待一個線程(誰輸入第一個)將完成迭代,然後第二個將開始和完成,但我得到不一致的輸出。

您得到的輸出不明白,但與您編寫的代碼一致。當您有​​方法時,您將鎖定封閉類的實例。

public class TestThr implements Runnable { 
    ... 
    public synchronized void sync() { 

在您的例子中,sync方法是​​所以它會鎖定的TestThr特定實例。你開始你的主題,如:

Thread t = new Thread(new TestThr()); 
Thread t1 = new Thread(new TestThr()); 

這意味着,每個線程都有自己的TestThr實例,以便它們被鎖在不同的情況下,不停止運行對方。

如果你不是做了以下內容:

final TestThr testThr = new TestThr(); 
Thread t = new Thread(testThr); 
Thread t1 = new Thread(testThr); 

現在的2個線程正在研究的TestThr同一實例,使他們對同一個對象被鎖定,你的輸出將是你所期望的。

這僅適用,因爲TestThr沒有任何存儲的字段。如果你需要一個更復雜的類,那麼我會傳遞一個鎖對象給他們。喜歡的東西:

final Object lockObject = new Object(); 
Thread t = new Thread(new TestThr(lockObject)); 
Thread t1 = new Thread(new TestThr(lockObject)); 

然後你的代碼中,你會怎麼做:

public void sync() { 
    synchronized (lockObject) { 
     ... 

所以這種方法不會被鎖定,但你會,而不是共享鎖對象上同步。

順便說一句,考慮到循環的大小,一個線程很可能啓動並運行循環,然後在另一個線程開始之前退出。把System.out.println(...)調用放慢線程,所以也許你會爭奪,但如果你刪除輸出,你需要擔心。由於線程之間的競爭條件,測試這樣的線程程序可能很困難。

+0

很好的解釋...謝謝!!! – dullpointer

0

正如@Pavlo Plynko所寫,您使用的是同步方法,但您爲Thread創建了兩個不同的對象。您應該創建單個實例,然後將此對象提供給您的線程。在這種情況下,兩個線程將使用同一個對象實例,並等待執行相同的方法。

以下代碼:

public class TestThr implements Runnable { 

public static void main(String[] args) { 
    TestThr synchronizedObject = new TestThr(); 
    Thread t = new Thread(synchronizedObject); 
    Thread t1 = new Thread(synchronizedObject); 

    t.start(); 
    t1.start(); 
} 

@Override 
public void run() { 
    System.out.println("Thread " + Thread.currentThread().getName() + " is waiting for execution"); 
    sync(); 
    System.out.println("Thread " + Thread.currentThread().getName() + " has executed synced method"); 
} 

public synchronized void sync() { 
    for (int i = 0; i < 10; i++) { 
     System.out.println("Running " + Thread.currentThread().getName()); 
    } 
} 
} 

將提供以下的輸出:

Thread Thread-0 is waiting for execution 
Thread Thread-1 is waiting for execution 
Running Thread-0 
Running Thread-0 
Running Thread-0 
Running Thread-0 
Running Thread-0 
Running Thread-0 
Running Thread-0 
Running Thread-0 
Running Thread-0 
Running Thread-0 
Thread Thread-0 has executed synced method 
Running Thread-1 
Running Thread-1 
Running Thread-1 
Running Thread-1 
Running Thread-1 
Running Thread-1 
Running Thread-1 
Running Thread-1 
Running Thread-1 
Running Thread-1 
Thread Thread-1 has executed synced method