2014-07-01 114 views
0

我有點困惑這個任務對我有螺紋:我有三大類:Java線程:同步的價值讀寫同一個對象

  • 存儲整數的類,我們稱之爲StoredInteger
  • 一個Thread類(IncrementThread)是應該遞增StoredInteger類的整數值
  • 另一個線程類(ReadThread)是應該讀取來自StredInteger
  • 整數值

的方法,所述方法應該去輸出應被同步,例如:

  • IncementThread值1寫入StoredInteger
  • ReadThread讀取值1從StoredInteger
  • IncementThread寫入值2到StoredInteger
  • ReadThreadStoredInteger讀取值...等等

我遇到的問題是,ReadThread等待IncrementThread完成,然後它只讀取最後一個值。以下是我的一些代碼:

public class ReadThread extends Thread { 

    private StoredInteger stored_integer; 
    ... 

    @Override 
    public void run() 
    { 
     int i = 0; 
     while(i < 100) 
     { 
      synchronized(this.getStoredInteger()) 
      { 
       try { 
        Thread.sleep(1000); 
       } catch (InterruptedException ex) { 
        ... 
       } 
       System.out.format("%s: Reading %d from StoredInteger\n", this.getClass().getSimpleName(), this.getStoredInteger().getValue()); 
       i++; 
      } 

     } 
    } 

    ... 
} 

public class IncrementThread extends Thread { 

private StoredInteger stored_integer; 

    ... 

    @Override 
    public void run() 
    { 
     int i = 0; 
     while(i < 100) 
     { 
      synchronized(this.getStoredInteger()) 
      { 
       try { 
        Thread.sleep(1000); 
       } catch (InterruptedException ex) { 
        ... 
       } 
       System.out.format("%s: Writing %d to StoredInteger\n", this.getClass().getSimpleName(), i); 
       this.getStoredInteger().setValue(i); 
       i++; 
      }   
     } 
    } 
    ... 
} 

而且運行的線程:

public static void main(String[] args) throws InterruptedException 
    { 
     StoredInteger intgr = new StoredInteger(); 
     Thread write = new Thread(new IncrementThread(intgr)); 
     Thread read = new Thread(new ReadThread(intgr)); 
     write.start(); 
     read.start(); 
     write.join(); 
     read.join(); 

    } 

我在做什麼錯在這裏?

謝謝!

回答

1

代碼中的任何內容都不能保證讀/寫線程交替工作。你基本上都有兩個線程進入互斥區。他們在那裏等待1秒鐘(保持鎖定)並寫入或讀取一個值。你可以在互斥區之外進行睡眠,但是再一次,它不能保證線程交替工作(儘管1秒的睡眠()幾乎可以確定它們會)。

@Override 
public void run() { 
    int i = 0; 
    while (i < 100) { 
     synchronized (stored_integer) { 
      System.out.format("%s: Writing %d to StoredInteger\n", this.getClass().getSimpleName(), i); 
      stored_integer.value = i; 
      i++; 
     } 

     try { 
      Thread.sleep(1000); 
     } catch (InterruptedException ex) { 
      // 
     } 
    } 
} 

@Override 
public void run() { 
    int i = 0; 
    while (i < 100) { 
     synchronized (stored_integer) { 
      System.out.format("%s: Reading %d from StoredInteger\n", this.getClass().getSimpleName(), stored_integer.value); 
      i++; 
     } 

     try { 
      Thread.sleep(1000); 
     } catch (InterruptedException ex) { 
     } 
    } 
} 

但是,要做到這一點,您需要使用wait()和notify()方法。編寫器線程在寫入後等待,以便讀者線程可以讀取並喚醒編寫器。例如:

@Override 
public void run() { 
    int i = 0; 
    while (i < 100) { 
     synchronized (stored_integer) { 
      System.out.format("%s: Writing %d to StoredInteger\n", this.getClass().getSimpleName(), i); 
      stored_integer.value = i; 
      i++; 

      // Writer wakes up writer 
      stored_integer.notify(); 

      // Writer waits until it can read 
      try { 
       stored_integer.wait(); 
      } catch (InterruptedException ex) { 
       // 
      } 
     } 
    } 
} 

@Override 
public void run() { 
    synchronized (stored_integer) { 
     // Reader waits for the first time! 
     try { 
      stored_integer.wait(); 
     } catch (InterruptedException ex) { 
      // 
     } 
    } 
    int i = 0; 
    while (i < 100) { 
     synchronized (stored_integer) { 

      System.out.format("%s: Reading %d from StoredInteger\n", this.getClass().getSimpleName(), stored_integer.value); 
      i++; 

      // Reader wakes up writer 
      stored_integer.notify(); 

      // If there are still more values to read 
      if (i < 100) { 
       // Reader waits until it can read 
       try { 
        stored_integer.wait(); 
       } catch (InterruptedException ex) { 
        // 
       } 
      } 
     } 
    } 
} 

在你的main上,首先在reader線程上使用start(),然後在writer線程上使用start()。即使那樣,代碼也可能不起作用。如果你的處理器不應該在來自writer的Notify()之前等待Reader(可能發生,因爲這些是線程,畢竟),你就會陷入僵局。解決這個問題的一種方法是在條件變量處等待(如果需要),並且只有在讀者被阻止等待它之後才啓動寫入器線程。

+0

這是問題!謝謝你的努力:) – Comforse

+1

用2個信號燈更容易 – Dimitri

+0

確實!我只是更習慣於監視器:P – BlueMoon93

1

您可能希望將睡眠呼叫移出同步塊,否則在睡眠時它仍然保持變量的鎖定。

1

嘗試在同步塊後放置thread.sleep

1

ReentrantReadWriteLock怎麼樣? 請參見java.util.concurrent.locks。

+0

ReentrantLock似乎是一個更有效的解決方案,可以保證執行線程的順序。上述答案建議的解決方案可以完成這項工作(我必須認識到,我需要做一些小的等待時間調整以保持訂單)。目前,建議的解決方案解決了我的任務,但我可以給你一個加號給你的建議,我一定會在將來使用它。謝謝! – Comforse