2014-10-05 89 views
0

即時試圖寫在其中創建兩個線程的程序,並且輸出應該像第一線程打印1和下一個線程打印2,第一線程再次打印3等。我是初學者,所以請幫助我清楚。我想線程共享相同的內存,所以他們將分享我的變量,並相應地打印。但在輸出我得到像thread1:1,thread2:1,thread1:2,thread2:2等等。請幫助。這裏是我的代碼多線程程序打印1到50的數字?

class me extends Thread 
{ 
public int name,i; 
public void run() 
{ 
    for(i=1;i<=50;i++) 
    { 
     System.out.println("Thread" + name + " : " + i); 
     try 
     { 
      sleep(1000); 
     } 
     catch(Exception e) 
     { 
      System.out.println("some problem"); 
     } 
    } 
} 
} 
public class he 
{ 
public static void main(String[] args) 
{ 
    me a=new me(); 
    me b=new me(); 
    a.name=1; 
    b.name=2; 
    a.start(); 
    b.start(); 
} 
} 
+4

你爲什麼想做這個數字? – 2014-10-05 00:40:32

+1

是的,你爲什麼要這樣做?這是一個家庭作業問題還是一些你想嘗試的隨機事物? – 2014-10-05 00:49:55

+1

那麼,你的變量'i'是一個局部變量,它只在循環內部和執行循環的線程內部可用。但是,你確定你希望你的兩個線程以書面形式交替嗎?你可以通過讓一個線程觸發另一個線程來實現這一點,反之亦然,但基本上可以讓你的程序順序運行。或者,你可以讓你的兩個線程以任意順序寫入,例如,Thread1寫入1,Thread1寫入2,Thread2寫入3,... **編輯**:對不起,實際上你的'i'不是局部變量,但你需要自動更新它。 – 2014-10-05 00:58:05

回答

0

首先你應該閱讀這個http://www.oracle.com/technetwork/java/codeconventions-135099.html。其次,類成員變量不是共享內存。您需要將對象(如計數器)顯式傳遞給兩個對象,以便它們變成共享對象。但是,這仍然不夠。共享內存可以被線程緩存,所以你將有競爭條件。爲了解決這個問題,你需要使用一個Lock或使用AtomicInteger

+0

我同意。如果Java 1.5+被定位,我會使用'AtomicInteger'。然後你可以獲得原子性,並且可以在該對象上使用同步並使用通知並等待信號使線程彼此鎖定(這樣輸出保持交錯狀態) – 2014-10-05 04:45:20

0

看來你想要做的是:

  • 寫從1到50的所有數字System.out
    • 沒有任何數爲被印刷的印刷多次
    • 與數字爲了
  • 有這個執行完成通過兩個併發線程

首先,讓我們來看看代碼中發生了什麼:每個數字都會打印兩次。這樣做的原因是,ime一個實例變量,你Thread。因此,每個Thread都有其自己的i,即它們不共享該值。

爲了使兩個線程共享相同的值,我們需要構建me時傳遞相同的值。現在,隨着原始int這樣做不會幫助我們很多,因爲傳遞一個int如果我們沒有一個參考,因此這兩個線程將仍然獨立的內存位置運行。

讓我們定義一個新的類,Value保存用於我們的整數:(編輯:同樣也可以通過傳遞數組int[],其也保持參考其內容的存儲位置來實現)

現在
class Value{ 
    int i = 1; 
} 

main可以實例Value類型的一個對象和參考將它傳遞給兩個線程。這樣,他們可以訪問相同的內存位置。

class Me extends Thread { 
    final Value v; 
    public Me(Value v){ 
    this.v = v; 
    } 
    public void run(){ 
    for(; v.i < 50; v.i++){ 
    // ... 
    } 

    public static void main(){ 
    Value valueInstance = new Value(); 
    Me a = new Me(valueInstance); 
    Me b = new Me(valueInstance); 
    } 
} 

i現在不兩次每次打印。但是,您會注意到行爲仍然不符合要求。這是因爲操作交錯:a可以讀取i,讓我們說,這個值是5.接下來,b遞增的i值,將新值。 i現在是6然而,a並仍讀舊值,5,並重新打印5,即使b剛剛打印5。

爲了解決這一點,必須鎖定實例v,即Value類型的對象。 Java提供了關鍵字​​,它將在執行​​塊內的所有代碼期間保持鎖定狀態。但是,如果你只是同步你的方法,你仍然不會得到你想要的。假設你寫:

public void run(){ synchronized(v) { 
    for(; v.i < 50; v.i++) { 
    // ... 
}} 

你的第一個線程將獲得鎖,但直到整個循環已經執行從不釋放它(這是當i的值爲50)。因此,您必須在安全的情況下以某種方式釋放鎖。嗯......你run方法的唯一代碼,不依賴於i(因此並不需要被鎖定)爲sleep,這也很幸運在這裏線程中花費時間最多的。

既然一切是在循環體中,一個簡單的​​塊將不會執行。我們可以使用Semaphore來獲得一個鎖。因此,我們在main方法中創建了一個Semaphore實例,並且與v類似,將它傳遞給兩個線程。然後,我們可以獲得並釋放對Semaphore的鎖定,讓兩個線程都有機會獲取資源,同時保證安全。

下面是將這樣的伎倆代碼:

public class Me extends Thread { 
    public int name; 
    final Value v; 
    final Semaphore lock; 

    public Me(Value v, Semaphore lock) { 
     this.v = v; 
     this.lock = lock; 
    } 

    public void run() { 
     try { 
      lock.acquire(); 
      while (v.i <= 50) { 
       System.out.println("Thread" + name + " : " + v.i); 
       v.i++; 
       lock.release(); 
       sleep(100); 
       lock.acquire(); 
      } 
      lock.release(); 
     } catch (Exception e) { 
      System.out.println("some problem"); 
     } 
    } 

    public static void main(String[] args) { 
     Value v = new Value(); 
     Semaphore lock = new Semaphore(1); 
     Me a = new Me(v, lock); 
     Me b = new Me(v, lock); 
     a.name = 1; 
     b.name = 2; 
     a.start(); 
     b.start(); 
    } 

    static class Value { 
     int i = 1; 
    } 
} 

注:由於我們是在循環的末尾獲取鎖,我們也必須在循環後釋放,或資源永遠不會釋放。另外,我將for -loop更改爲while循環,因爲我們需要在第一次釋放鎖之前更新i,或者其他線程可以再次讀取相同的值。

-1

查看下面的鏈接瞭解該解決方案。使用多線程我們可以打印升序

http://cooltekhie.blogspot.in/2017/06/#987628206008590221

+1

如果僅僅因爲第一個獲得鎖的線程永遠不會屈服。這已經夠糟糕了,但是它會等待被通知,永遠不會完成,因爲通知線程(如果不是主線程永遠不放棄鎖定)。修復仍然不行,因爲絕對不能保證線程將被稱爲循環正如問題所要求的那樣 – Persixty 2017-06-30 15:35:07

+1

請避免發佈只有鏈接的答案您應該總結文章的相關部分,以便您的答案本身足以回答問題,這有助於確保答案仍然有用如果鏈接在未來的某個時候死亡。 – avojak 2017-06-30 15:59:55