1) 基础版本
public class AccountService {
public boolean transfer(final Account from, final Account to, final int amount) throws LockException, InterruptedException {
final Account[] accounts = new Account[] {from, to};
Arrays.sort(accounts);
if(accounts[0].monitor.tryLock(1, TimeUnit.SECONDS)) {
try {
if (accounts[1].monitor.tryLock(1, TimeUnit.SECONDS)) {
try { if(from.withdraw(amount)) {
to.deposit(amount);
return true; } else {
return false;
}
} finally { accounts[1].monitor.unlock();} }
} finally { accounts[0].monitor.unlock();
} }
throw new LockException("Unable to acquire locks on the accounts");
}
}
2) Akka STM java
public void transfer(
final Account from, final Account to, final int amount) {
new Atomic() {
public Boolean atomically() {
to.deposit(amount);
from.withdraw(amount);
return true;
}
}.execute();
}
3) Akka STM Scala
Account.scala
package STM;
import scala.concurrent.stm.Ref
import scala.concurrent.stm.atomic
class AccountOperationFailedException extends Exception
class Account(val initialBalance: Int)
{
val balance = Ref(initialBalance)
def getBalance() = balance.single()
def deposit(amount : Int) = {
atomic {
implicit tx => {
if(amount > 0 ){
balance.swap(balance() + amount)
} else {
throw new AccountOperationFailedException()
}
}
}
}
def withdraw(amount : Int) = {
atomic {
implicit tx => {
val currentBalance = balance()
if( amount >0 && currentBalance >= amount)
{
balance.swap(currentBalance - amount)
} else {
throw new AccountOperationFailedException()
}
}
}
}
}
AccountService.scala
package STM
import scala.concurrent.stm.Ref
import scala.concurrent.stm.atomic
/**
* @author ppeng
*/
object AccountService {
def transfer(from : Account, to: Account, amount: Int) = {
atomic {
implicit tx => {
println("Attempting transfer...")
to.deposit(amount)
println("Uncommitted balance after deposit $" + to.getBalance())
from.withdraw(amount)
}
}
}
def transferAndPrintBalance(from : Account, to : Account, amount : Int) = {
var result = "Pass"
try {
AccountService.transfer(from, to, amount)
} catch {
case ex : Throwable => result = "Fail"
}
println("Result of transfer is " + result)
println("From account has $" + from.getBalance())
println("To account has $" + to.getBalance())
}
def main(args : Array[String]) = {
val account1 = new Account(2000)
val account2 = new Account(2000)
Thread.sleep(1000)
account2.deposit(20)
AccountService.transferAndPrintBalance(account1, account2, 500)
AccountService.transferAndPrintBalance(account1, account2, 5000)
}
}