?? trans.html
字號:
<html><!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><html> <head><title>Transactions</title></head><BODY bgcolor=#ffffee vlink=#0000aa link=#cc0000><h1>Transactions</h1>Transaction control is an extension of guard-based design in which<em>arbitrary</em> sets of method calls on one or more objects need tobe performed as an atomic unit, without interference from otherthreads. There are hundreds of strategies for performing Transactions,especially in the context of Databases. (see for example <AHREF="javascript:if(confirm('http://g.oswego.edu/dl/oosdw3/ch22/ch22.html \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address. \n\nDo you want to open it from the server?'))window.location='http://g.oswego.edu/dl/oosdw3/ch22/ch22.html'" tppabs="http://g.oswego.edu/dl/oosdw3/ch22/ch22.html">OOSD</A> for someintroductory discussion and references to the literature.) Here, wewill focus on a few in-the-small coding idioms encountered within thecontext of multithreaded Java applications.<p>To use a classic example, suppose we have <code>BankAccount</code>objects of the stripped-down form:<pre>class InsufficientFunds extends UserException {};class BankAccount { private double balance_; public BankAccount() { balance_ = 0.0; } public synchronized double balance() { return balance_; } public synchronized void deposit(double amount) throws InsufficientFunds { if (amount >= 0.0 || balance_ >= -amount) balance_ += amount; else throw new InsufficientFunds(); } public synchronized void withdraw(double amount) throws InsufficientFunds { deposit(-amount); }} </pre>Now, even though objects of class <code>BankAccount</code> performeach of their individual actions atomically (because of the use of<code>synchronized</code>), this does not provide enough protectionwhen you are trying to write code that must atomically execute severalmethods as a single group. For an example, here's an initial (andwrong/incomplete) attempt to write a method that transfers money fromone account to another:<pre>class WrongAccountUser { ... TransactionLogger log_; public synchronized boolean transfer(double amount, BankAccount source, BankAccount destination) { if (source.balance() >= amount) { // (*) log_.logTransfer(amount, source, destination); source.withdraw(amount); // (**) destination.deposit(amount); return true; } else return false; }}</pre>The most glaring problem with this code is that even though the<code>source</code> account may have had enough money during the checkat line <code>(*)</code>, this might no longer be true by the time the<code>withdraw</code> method is called at line <code>(**)</code>,because some other thread caused the balance to change.<p> There are a two basic approaches for handling this in Java (aswell as various mixtures): per-block synchronization and exceptions.<h3>Block Synchronization</h3>In Java, any method code can ``grab'' the synchronization lock for anyobject and hold it during the execution of some code block. (SinceJava synchronization lock access is per-thread, not per object,additional calls to synchronized methods for the held objects willstill work; however, it is still good practice to avoid obtaining alock on the same object in more than one way, which is oftensymptomatic of an <ahref="javascript:if(confirm('http://g.oswego.edu/dl/oosdw3/ch22/ch22.html \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address. \n\nDo you want to open it from the server?'))window.location='http://g.oswego.edu/dl/oosdw3/ch22/ch22.html'" tppabs="http://g.oswego.edu/dl/oosdw3/ch22/ch22.html"> aliasing</a>problem.) So one way to obtain transactional behavior is to hold thelocks of all objects involved in the methods. For example:<pre>class AccountUser2 { TransactionLogger log_; ... public synchronized boolean transfer(double amount, BankAccount source, BankAccount destination) { if (source == destination) return true; // don't bother using synch code synchronized(source) { synchronized(destination) { // (***) if (source.balance() >= amount) { try { log_.logTransfer(amount, source, destination); source.withdraw(amount); destination.deposit(amount); return true; } catch (InsufficientFunds ex) { throw new Error("Can't happen!"); } } } } return false; }}</pre>The main danger with this approach is that it is much more susceptibleto <a href="synchDesign.html" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/synchDesign.html">deadlock</a> than are mostsynchronization-based designs. In the majority of ``ordinary''synchronization-based designs, lock-ups happen only under incorrect orunintended usage, but here, deadlock is very possible under normaluse. Imagine the consequences of two threads, one trying to transfermoney from account <code>mine</code> to <code>yours</code>, and theother one doing the opposite. In this case, it is possible that atline <code>(***)</code> one thread will have the lock for<code>mine</code>, and be waiting for <code>yours</code>, but theother thread will already have <code>yours</code>, and be waiting for<code>mine</code>, leading to infinite waits.<p> Most database systems use various lock-monitoring schemes that candeal with this problem, but none of them seem to apply to Java'sintrinsic object locks, so to use them, you'd have to first build asecond-level locking framework.<p> However, one technique that does apply in small-scale use is<em>resource ordering</em>. If each object that can ever be held inthis kind of nested <code>synchronized</code> block is given a number(or any other orderable tag), and all code using such objects always grablocks in least-first order according to this numbering, then this formof deadlock cannot occur. (For more details, see, for example, GregoryAndrews <em>Concurrent Programming</em>, Benjamin Cummings, 1991).<h3>Exceptions and Rollbacks</h3>Rather than relying on synchronization and waiting, you can useexception mechanics to try to perform transactions, rollingback state as necessary upon failure. For example:<pre>class AccountUser3 { ... TransactionLogger log_; public synchronized boolean transfer(double amount, BankAccount source, BankAccount destination) { log_.logTransfer(amount, source, destination); try { source.withdraw(amount); } catch (InsufficientFunds ex) { log_.cancelLogEntry(amount, source, destination); return false; } try { destination.deposit(amount); } catch (InsufficientFunds ex) { throw new Error("Can't happen!"); } return true; }}</pre>As here, when using exceptions, check-and-act sequences can bereplaced with try-but-be-prepared-to-fail sequences. In the example,there's not much reason to bother pre-checking whether<code>source</code> has sufficient funds, since even if it reportstrue, the <code>withdraw</code> attempt may fail anyway. (One reasonto do the check anyway is to reduce the likelihood of causing anexception, which might be a good idea since exceptions are relativelyexpensive compared to simple branching.)<p>In this example, there is not much that needs to be rolled backupon failure. In fact the log-cancellation could even be avoidedif it were OK to log transfers only upon success, in which casethe call could be moved down beyond the failure point.<p> However, in general, exception-based handling works well only whenyou can reasonably define the notion of rollback. For operations that``change the world'' (for example, activate physical devices) ratherthan internal states of software objects, this is at best a challenge.In these cases you typically have to rely upon synchronization-baseddesigns instead.<p><a href="aopintro.html" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/aopintro.html">[Concurrent Programming in Java]</a><hr><address><A HREF="javascript:if(confirm('http://g.oswego.edu/dl \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address. \n\nDo you want to open it from the server?'))window.location='http://g.oswego.edu/dl'" tppabs="http://g.oswego.edu/dl">Doug Lea</A></address><!-- hhmts start -->Last modified: Tue Feb 20 06:29:00 EST 1996<!-- hhmts end --></body> </html>
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -