2013-05-05 129 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(); 
     } 
    } 
} 

在这种情况下,多个线程可以读一次平衡,但只有一个线程。