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;
}
  }

我有两个线程: 存款人:

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);
    }
}
}

和取款机:

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();
        }
    }
}
4

2 回答 2

0

我不确定是否正确地发现了你的问题,但我会试一试。

您的 Account 类已经是线程安全的,因为您正在为提款和存款方法使用“同步”关键字。当调用“同步”方法时,它会锁定“this”,因此对于“帐户”的一个实例,任何两个“同步”方法都不会同时运行。但是,如果您希望能够读取一个帐户的余额,您应该添加一个也同步的访问器。在这种情况下,一次只能由一个线程读取余额,这可以通过使用“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();
        }
    }
}

在这种情况下,一次可以有多个线程读取余额,但一次只有一个线程可以更改余额。

于 2013-05-05T12:38:43.600 回答
0

在您的示例中使用信号量可能如下所示:

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 秒即可获得许可,如果没有发生则抛出异常。

于 2013-05-05T13:08:25.887 回答