2012-05-19 110 views
4

我跑以下代碼:同步方法,而使用的等待()

class Counter extends Thread { 

static int i=0; 
//method where the thread execution will start 
public void run(){ 
    //logic to execute in a thread 

    while (true) { 
     increment(); 
    } 
} 

public synchronized void increment() { 
    try { 
     System.out.println(this.getName() + " " + i++); 
     wait(1000); 
     notify(); 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

} 
//let’s see how to start the threads 
public static void main(String[] args){ 
    Counter c1 = new Counter(); 
    Counter c2 = new Counter(); 
    c1.setName("Thread1"); 
    c2.setName("Thread2"); 
    c1.start(); 
    c2.start(); 
} 
} 

是此代碼的結果(添加的行編號):

1: Thread1 0 
2: Thread2 1 
3: Thread2 2 
4: Thread1 3 
5: Thread2 4 
6: Thread1 4 
7: Thread1 5 
8: Thread2 6 
stopping... 

由於增量方法是同步的並且由於其包含等待(1000)我沒有預料到: 1.線程2打印2個連續打印:行2,3 我預計線程交錯他們的打印 2.在第5,6行我仍然是4.

任何人都可以給我一個解釋嗎?

回答

1

您只在實例級同步。要同步所有Counter實例,您需要的increment方法爲static以及​​。

由於它表示所有線程都可以自由運行,併發運行,因爲它們不共享同步機制。

+2

代碼或者你需要是常見的兩種'Thread'情況下,在同一對象上同步。爲此靜態方法看起來像一個黑客。 – Gray

+0

@Gray - 是的,添加了更新 –

8

同步實例方法是這樣的:

public synchronized void foo() { 
    ... 
} 

大致相當於:

public void foo() { 
    synchronized(this) { 
     ... 
    } 
} 

你看到這裏的問題?同步在當前實例上完成。

由於您正在創建兩個單獨的Thread對象,因此每個increment方法將同步到一個不同的對象上,從而導致鎖無效。

您應該讓您的增量方法靜態的(因此鎖定類本身完成的),或者使用一個靜態鎖定對象:

private static final Object locker = new Object(); 

public void foo() { 
    synchronized(locker) { 
     ... 
    } 
} 

而且最後一個建議:在創建線程的首選方式java是通過執行Runnable,而不是擴展Thread

+0

並且更好地使用java.util.concurrent.locks.Lock API,並且您可能想要使用條件('lock.newCondition()')在線程之間進行通信。 –

+0

如果我通過實現Runnable來重寫這個,我怎麼能在打印時訪問線程的名字? – Elad

+0

@Elad:和以前一樣。只有'Counter c1 = new Counter();'變爲'Thread t1 = new Thread(new Counter());''Counter'現在只是實現'Runnable'。那麼你可以像't1.setName(「Thread1」);''一樣。 – Tudor

0

這可能是你正在尋找

class Counter implements Runnable { 

    static int i = 0; 
    private Lock lock; 
    private Condition condition; 

    public Counter(Lock lock, Condition condition) { 

     this.lock = lock; 
     this.condition = condition; 
    } 


    public void run() { 
     while (true) { 
      lock.lock(); 
      try { 
       condition.await(1, TimeUnit.SECONDS); 
       System.out.append(Thread.currentThread().getName()).append(" ").println(i++); 
       condition.signalAll(); 
      } catch (InterruptedException e) { 
       throw new RuntimeException(e); 
      } 
     } 
    } 

    public static void main(String[] args) { 
     Lock lock = new ReentrantLock(true); 
     Condition condition = lock.newCondition(); 
     Executor e = Executors.newFixedThreadPool(2); 
     e.execute(new Counter(lock, condition)); 
     e.execute(new Counter(lock, condition)); 

    } 
} 
+0

謝謝!解決了在靜態方法中調用wait()的問題! – Elad