知识库--The Write Skew Anomaly Fixed By Akka(136)

    xiaoxiao2021-03-25  134

    /** 两个账户总和大于等于1000才能取款 In Handling Write Skew Anomaly, we discussed write skew and how Clojure STM handles it. Akka also has support for dealing with write skew, *but we have to configure it*. OK, that word may sound scary, but it’s really simple. Let’s first see the default behavior without any configuration. Let’s revisit the example of multiple accounts with a restricted combined balance that we looked at earlier. Create a Portfolio class that holds a checking account balance and a savings account balance. These two accounts have a constraint of the total balance not running less than $1,000. This class along with the withdraw() method is shown next. In this method, we obtain the two balances first, compute their total, and after a intentional delay (introduced to set transactions on collision course) we subtract the given amount from either the checking balance or the savings balance if the total is not less than $1,000. The withdraw() method does its operations within a transaction configured using default settings. */ public class Portfolio { final private Ref<Integer> checkingBalance = new Ref<Integer>(500); final private Ref<Integer> savingsBalance = new Ref<Integer>(600); public int getCheckingBalance() { return checkingBalance.get(); } public int getSavingsBalance() { return savingsBalance.get(); } public void withdraw(final boolean fromChecking, final int amount) { new Atomic<Object>() { public Object atomically() { final int totalBalance =checkingBalance.get() + savingsBalance.get(); try { Thread.sleep(1000); } catch(InterruptedException ex) {} if(totalBalance - amount >= 1000) { if(fromChecking) checkingBalance.swap(checkingBalance.get() - amount); else savingsBalance.swap(savingsBalance.get() - amount); } else System.out.println( "Sorry, can't withdraw due to constraint violation"); return null; } }.execute(); } } //test public class UsePortfolio { public static void main(final String[] args) throws InterruptedException { final Portfolio portfolio = new Portfolio(); //init int checkingBalance = portfolio.getCheckingBalance(); int savingBalance = portfolio.getSavingsBalance(); System.out.println("Checking balance is " + checkingBalance); System.out.println("Savings balance is " + savingBalance); System.out.println("Total balance is " + (checkingBalance + savingBalance)); final ExecutorService service = Executors.newFixedThreadPool(10); service.execute(new Runnable() { public void run() { portfolio.withdraw(true, 100); } }); service.execute(new Runnable() { public void run() { portfolio.withdraw(false, 100); } }); service.shutdown(); Thread.sleep(4000); checkingBalance = portfolio.getCheckingBalance(); savingBalance = portfolio.getSavingsBalance(); System.out.println("Checking balance is " + checkingBalance); System.out.println("Savings balance is " + savingBalance); System.out.println("Total balance is " + (checkingBalance + savingBalance)); if(checkingBalance + savingBalance < 1000) System.out.println("Oops, broke the constraint!"); } }

    解析: By default, Akka does not avoid write skew, and the two transactions will proceed running the balances into constraint violation, as we see in the output: 结果1 :

    Checking balance is 500 Savings balance is 600 Total balance is 1100 Checking balance is 400 Savings balance is 500 Total balance is 900 Oops, broke the constraint!

    FIX:

    new Atomic<Object>() { to the following: akka.stm.TransactionFactory factory = new akka.stm.TransactionFactoryBuilder() .setWriteSkew(false) .setTrackReads(true) .build(); new Atomic<Object>(factory) {...

    We created a TransactionFactoryBuilder and set the writeSkew and trackReads properties to false and true, respectively. This tells the transaction to keep track of reads within a transaction and also to set a read lock on the reads until the commit begins, just as Clojure STM handles ensure.

    转载请注明原文地址: https://ju.6miu.com/read-8205.html

    最新回复(0)