2011-04-11 55 views
2

打印出來的數字我正在學習如何在Java線程工作,我需要一些建議..Java線程同步 - 在正確的順序

我想在標準輸出數字打印從0..50使用三個線程完成它的線程的名稱。

我有兩個類 - 類反是實現Runnable和類主要創建並運行線程。計數器具有在線程之間共享的變量c

我的想法是,我加1 ç,然後調用收益率()當前線程上,以便其他線程會做同樣的。重複此操作直到c達到50.

但是它沒有工作,數字按錯誤順序打印出來。我該如何解決?

public class Counter implements Runnable { 

Thread t1; 
private int c = -1; 

public Counter() { 
} 

public Counter(String name) { 
    t1 = new Thread(this, name); 
    t1.start(); 
} 

@Override 
public void run() { 
    while (c < 50) { 
     increment(); 
     Thread.yield(); 
    } 
} 

public void increment() { 
    if (c < 50) { 
     c++; 
     System.out.println(Thread.currentThread().getName() + ": " + c); 
    } 
} 
} 

public class Main { 

public static void main(String[] args) throws IllegalThreadStateException { 
    Counter c1 = new Counter(); 
    Thread t1 = new Thread(c1, "Thread 1"); 
    Thread t2 = new Thread(c1, "Thread 2"); 
    Thread t3 = new Thread(c1, "Thread 3"); 

    t1.start(); 
    t2.start(); 
    t3.start(); 

} 

編輯:最後我解決了這個問題。感謝所有幫助我開展多線程開局的人。

import java.util.concurrent.atomic.AtomicInteger; 

public class Counter2 implements Runnable { 

// you could also use simple int 
private AtomicInteger c = new AtomicInteger(-1); 
private static final Object syncObject = new Object(); 

public Counter2() { 
} 

@Override 
public void run() { 
    while (c.get() < 50) { 
     synchronized (syncObject) { 
      if (c.get() < 50) { 
       System.out.println(Thread.currentThread().getName() + ": " + c.incrementAndGet()); 
      } 
     } 
    } 
}  
} 
+0

你可以發佈一些他們正在打印的例子嗎? – Argote 2011-04-11 10:02:03

+0

你試過AtomicInteger嗎? – 2011-04-11 10:03:59

+0

我認爲這是隨機的.. – 2011-04-11 10:04:30

回答

2

在帶有特殊靜態對象的方法增量中使用syncrhonized節。

private static final Object syncObj = new Object(); 

public void increment() 
{ 
    syncrhonized(syncObj) 
    { 
    c++; 
    System.out.println(c); 
    } 
} 

或者通過聲明使該方法同步。

但是,將實際數據存儲在線程對象中是錯誤的想法。主題應該只操縱與分享的對象,但不能將其保存\ 而實際上我不明白你爲什麼開始

1

使increment()同步以防止其他線程同時進入該方法。

結合yield()您應該可以得到另一個線程打印下一個數字(並非總是,因爲系統可能會重新啓動yield的線程 - 請參閱Ingo的答案 - 但順序應該仍然相同)。

synchronized increment()意味着任何嘗試在同一對象上輸入該方法的線程將不得不等待,如果另一個線程已經通過輸入方法獲得了鎖定。

+0

只能通過線程1完成 – 2011-04-11 10:04:10

+0

你還在使用yield()嗎? – Thomas 2011-04-11 10:06:58

1

線程的Javadoc Thread.yield()引用,強調由我:

public static void yield() 

一個提示,該 當前線程願意,得到其 當前使用的處理器的調度器。 調度程序可以自由忽略此 提示

...

這是很少適當使用 此方法。

1

是的,你的代碼將無法正常工作。線程#yield()不會以您所期望的方式控制線程調度器。我很好奇你會得到什麼樣的結果,你可能會得到重複的數字和一些數量有點不符合的數字

你可以使用原子整數,它應該刪除所有重複項,但由於print語句不是原子的。你可能仍然按順序打印你的結果,所以你可能應該只是同步增量方法,而且你並不需要產量,所以它可以轉儲它

如果問題的目的是從線程1轉到線程2線程3回到線程1,等...這樣的結果是

Thread 1:0 
Thread 2:1 
Thread 3:2 
Thread 1:3 
Thread 2:4 
Thread 3:5 
Thread 1:6 
Thread 2:7 
.... 

然後,你需要鎖定在crement方法並使用wait和notifyAll。等待會導致其他線程停止處理,直到當前線程通知他們再次啓動。