2013-05-05 121 views
0

美好的一天!使用信號量進行多線程處理

我需要使用信號量解決同步問題。我讀過很多教程,現在我知道我應該使用釋放方法並獲取方法,但是,我不知道在代碼中使用它們的位置。你能幫我一下,或者聯繫我一個有用的教程。 我有類賬戶:

public class Account { 
    protected double balance; 

    public synchronized void withdraw(double amount) { 
    this.balance = this.balance - amount; 
} 

public synchronized void deposit(double amount) { 
    this.balance = this.balance + amount; 
} 
    } 

我有兩個線程:Depositer:

public class Depositer extends Thread { 
    // deposits $10 a 10 million times 
    protected Account account; 

public Depositer(Account a) { 
    account = a; 
} 

@Override 
public void run() { 
    for(int i = 0; i < 10000000; i++) { 
     account.deposit(10); 
    } 
} 
} 

而且Withdrawer:

public class Withdrawer extends Thread { 

    // withdraws $10 a 10 million times 
    protected Account account; 

public Withdrawer(Account a) { 
    account = a; 
} 

@Override 
public void run() { 
    for(int i = 0; i < 1000; i++) { 
     account.withdraw(10); 
    } 
} 
} 

這裏是主要的:

public class AccountManager { 
     public static void main(String[] args) {   
    // TODO Auto-generated method stub 

    Account [] account = new Account[2]; 
    Depositor [] deposit = new Depositor[2]; 
    Withdrawer [] withdraw = new Withdrawer[2]; 

    // The birth of 10 accounts 
    account[0] = new Account(1234,"Mike",1000); 
    account[1] = new Account(2345,"Adam",2000); 

    // The birth of 10 depositors 
    deposit[0] = new Depositor(account[0]); 
    deposit[1] = new Depositor(account[1]); 


    // The birth of 10 withdraws 
    withdraw[0] = new Withdrawer(account[0]); 
    withdraw[1] = new Withdrawer(account[1]); 


      for(int i=0; i<2; i++) 
      { 
       deposit[i].start(); 
       withdraw[i].start(); 
      }    

    for(int i=0; i<2; i++){ 
     try { 
      deposit[i].join(); 
      withdraw[i].join(); 
     } 
        catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
} 
+0

你能解釋信號量如何對帳戶有幫助嗎?他們通常使用通常使用的鎖來實現。 BTW通常錢從某個地方轉移到別的地方。它不會像您在示例中那樣創建或銷燬。 – 2013-05-05 12:08:45

+0

@PeterLawrey您可以存入支票並在ATM取款;-) – assylias 2013-05-05 12:09:46

+0

我建議嘗試先將問題本地化,然後以短代碼的形式發佈。 – 2013-05-05 12:15:58

回答

0

使用您例如semapahore看起來是這樣的:

import java.util.concurrent.Semaphore; 

public class Account { 
    private Semaphore semaphore = new Semaphore(1); 
    private double balance = 0; 

    public void withdraw(double amount){ 
    deposit(amount * -1); 
    } 

    public void deposit(double amount){ 
    semaphore.acquireUninterruptibly(); 
    balance += amount; 
    semaphore.release(); 
    } 
} 

這個例子很相似語義上的同步鎖之一,因爲它建立了一個信號量每賬戶實例(類似於現有的單一互斥用於鎖定對象實例)。它也會不間斷地(即永遠)等待獲取許可證,類似於試圖獲取對象上鎖的機罩代碼。如果你不想永遠等待,你可以在你的IMPL改變這樣的事情:

import java.util.concurrent.Semaphore; 
import java.util.concurrent.TimeUnit; 

public class Account { 
    private Semaphore semaphore = new Semaphore(1); 
    private double balance = 0; 

    public void withdraw(double amount){ 
    deposit(amount * -1); 
    } 

    public void deposit(double amount){ 
    try { 
     semaphore.tryAcquire(1, TimeUnit.SECONDS); 
     balance += amount; 
     semaphore.release(); 
    } 
    catch (InterruptedException e) { 

     //Probably want to throw a more specific exception type here... 
     throw new RuntimeException("Timed out waiting for an account balance..."); 
    } 
    } 
} 

在這個例子中,你將只需要1秒鐘的獲取許可,並拋出如果一個異常不會發生。

0

我不知道是否抓住了你的概率lem正確,但我會給它一個鏡頭。

您的帳戶類已經線程安全,因爲您正在使用'synchronized'關鍵字作爲提取和存款方法。當調用'synchronized'方法時,它鎖定'this',所以任何兩個'synchronized'方法永遠不會同時運行一個'Account'實例。 但是,如果您希望能夠讀取一個帳戶的餘額,您應該添加一個同步的存取器。在這種情況下,餘額一次只能被一個線程讀取,這可以通過使用'ReentrantReadWriteLock'來改變。這裏是你將如何使用它的代碼:一次可能改變平衡

class Account { 
    private double balance; 
    private ReentrantReadWriteLock balanceLock = new ReentrantReadWriteLock(); 

    public void withdraw(double amount) { 
     try { 
      balanceLock.writeLock().lock(); 
      this.balance = this.balance - amount; 
     } 
     finally { 
      balanceLock.writeLock().unlock(); 
     } 
    } 

    public void deposit(double amount) { 
     try { 
      balanceLock.writeLock().lock(); 
      this.balance = this.balance + amount; 
     } 
     finally { 
      balanceLock.writeLock().unlock(); 
     } 
    } 

    public double getBalance() { 
     try { 
      balanceLock.readLock().lock(); 
      return this.balance; 
     } 
     finally { 
      balanceLock.readLock().unlock(); 
     } 
    } 
} 

在這種情況下,多個線程可以讀一次平衡,但只有一個線程。