1. Trang chủ
  2. » Công Nghệ Thông Tin

Patterns in JavaTM, Volume 3 Java Enterprise Java Enterprise Design Patterns phần 8 doc

50 199 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 50
Dung lượng 363,11 KB

Nội dung

listing of the TransactionParticipantIF interface. All objects that par- ticipate in a transaction must either directly implement the Transaction- ParticipantIF interface or be wrapped by an adapter object that implements the TransactionParticipantIF interface. public interface TransactionParticipantIF { /** * This method does not return until it can associate a * lock on the participating object with the current * thread. */ public void lock() ; /** * Return an object that encapsulates the state of the * participating object. */ public SnapshotIF captureState() ; /** * Restore the state of the participating object from the * information encapsulated in the given object. The given * object must have previously been returned by this * object’s captureState method. */ public void restoreState(SnapshotIF state) ; /** * Release a previously obtained lock. */ public void unlock() ; } // interface TransactionParticipantIF Here is a listing of the TransactionManager class. An interesting thing about the TransactionManager class is that it delegates most of its work to a private inner class called Transaction. When a transaction is started, a TransactionManager object creates and associates a Transaction object with the current thread. This organization is based on the assumption that transactions are single-threaded. Every time a TransactionManager object is asked to do something, it uses the Transaction object that it previously created for the current thread. public class TransactionManager { private ThreadLocal myStack; private ThreadLocal currentTransaction; The myStack instance variable associates a Stack object with the cur- rent thread. The stack is used to save the values of objects when they are locked. The currentTransaction instance variable associates the current transaction a thread is working on with that thread. If the transaction is 342 ■ CHAPTER SEVEN nested in another transaction, its enclosing transaction is saved on the stack. The TransactionManager class’s constructor initializes these variables. public TransactionManager() { myStack = new ThreadLocal(); myStack.set(new Stack()); currentTransaction = new ThreadLocal(); } // TransactionManager() /** * Start a new transaction. If there is a transaction in * progress, the transactions nest. */ public void startTransaction() { getStack().push(getCurrentTransaction()); setCurrentTransaction(new Transaction()); } // startTransaction() A TransactionManager object delegates most of the work of its other operations to the current thread’s current Transaction object. /** * Add an object to the current transaction. */ public void enroll(TransactionParticipantIF obj) { checkCurrentTransaction(); getCurrentTransaction().enroll(obj); } // enroll(TransactionParticipantIF) /** * Commit the current transaction. */ public void commit() { checkCurrentTransaction(); getCurrentTransaction().commit(); } // commit() /** * Abort the current transaction. */ public void abort() { checkCurrentTransaction(); getCurrentTransaction().abort(); } // abort() Here are helper methods that are used by the preceding public methods. /** * Throw an <code>IllegalStateException</code> if there is * no current transaction. */ private void checkCurrentTransaction() { if (getCurrentTransaction()==null) { throw new IllegalStateException("No transaction"); Concurrency Patterns ■ 343 } //if } // checkCurrentTransaction() /** * Return the transaction manager stack associated with the * current thread. */ private Stack getStack() { return (Stack)myStack.get(); } // getStack() /** * Return the current Transaction object. */ private Transaction getCurrentTransaction() { return (Transaction)currentTransaction.get(); } // getCurrentTransaction() /** * Set the current Transaction object. */ private void setCurrentTransaction(Transaction t) { currentTransaction.set(t); } //setCurrentTransaction(Transaction) Transactions are represented as instances of this private class: private class Transaction { // Collection of TransactionParticipantIF objects. private ArrayList participants = new ArrayList(); /** * Add the given object to this transaction to be * modified. */ void enroll(TransactionParticipantIF obj) { obj.lock(); getStack().push(obj.captureState()); participants.add(obj); } // enroll(TransactionParticipantIF) /** * commit this transaction. */ void commit() { int count; count = participants.size(); for (int i=count-1; i>=0; i ) { TransactionParticipantIF p; p = (TransactionParticipantIF) participants.get(i); p.unlock(); getStack().pop(); 344 ■ CHAPTER SEVEN } // for Transaction prevTransaction; prevTransaction = (Transaction)getStack().pop(); setCurrentTransaction(prevTransaction); } // commit() /** * Abort this transaction. */ void abort() { int count; count = participants.size(); for (int i=count-1; i>=0; i ) { SnapshotIF state; state = (SnapshotIF)getStack().pop(); TransactionParticipantIF participant =(TransactionParticipantIF)participants.get(i); participant.restoreState(state); participant.unlock(); } // for setCurrentTransaction((Transaction)getStack().pop()); } // abort() } // class Transaction } // class TransactionManager RELATED PATTERNS ACID Transaction. The ACID Transaction pattern contains more information about the atomic and isolated properties of trans- actions. Decorator. The logic for a TransactionParticipantIF interface for a class that participates in a transaction is often imple- mented using the Decorator pattern (described in Volume 1). Snapshot. The Transaction State Stack pattern uses the Snapshot pattern (described in Volume 1) to encapsulate the current state of an object in a way suitable for being put on a stack and possi- bly being restored later. Concurrency Patterns ■ 345 CHAPTER Temporal Patterns 347 Time Server (349) Versioned Object (355) Temporal Property (373) The patterns in this chapter describe ways that applications manage time-related data. There are only a few patterns in this chapter. That should not be taken to mean that handling time is a simple matter. Issues related to handling and modeling time can be very complex. The small number of patterns is a symptom that the state of the art related to time is less well developed than other areas. 8 This pattern was previously described in [Lange98]. SYNOPSIS In order for some distributed applications to function correctly, the clocks on the computers they run on must be synchronized. Ensure that clocks on multiple computers are synchronized by synchronizing them with a common clock. CONTEXT You are designing an employee timekeeping system. The system architecture will include multiple timekeeping terminals. Employees will use the timekeeping terminals to indicate when they begin working a shift, are done working, and other timekeeping events. The terminals report timekeeping events to a server that collects the events in a database. Employees may use different timekeeping terminals to indicate the beginning of a shift and the end of a shift. When a timekeeping terminal reports a timekeeping event, the time of the event is determined by the timekeeping terminal’s own clock. If the clocks on the different terminals are not synchronized, the duration of the employee’s shift will appear to be longer or shorter than it actually was. FORCES ⁄ An application is distributed over multiple computers. ⁄ A distributed application is required to do things at predetermined times, to ensure the relative order of its actions. If the clocks on the computers an application is running on are not synchronized, their differences can cause the application to perform its actions in the wrong relative order. ⁄ A distributed application records events it receives on different computers. It is important to accurately determine the elapsed time Temporal Patterns ■ 349 Time Server between events, even if the events are received on different computers. ⁄ Relying on the continuous availability of a single central clock to determine the time that an event occurs can reduce the availability of an application, since the application will be unable to function if the clock becomes unavailable. Relying on a single central clock can also limit the performance of a distributed application, since relying on a central clock or any other central resource can result in that resource’s becoming a bottleneck. Ÿ Relying on a remote clock can introduce inaccuracies into the deter- mination of the time if the network delays encountered in communi- cating with the clock vary in an unpredictable way. SOLUTION Have each computer that hosts part of a distributed application periodi- cally set its own clock from the clock of a remote computer that functions as a time server. The frequency with which a host synchronizes its clock with the time server should be often enough that the clocks do not noticeably diverge. Typically, this is once every hour or two. Though this is more frequent than may be required to keep clocks synchronized, it serves to minimize the consequences of the time server’s being unavailable when another com- puter wants to synchronize its clock with the time server’s. Communication between a computer requesting the current time and a time server takes some amount of time. There is no way to know in advance exactly how long it will take. After a computer has requested the current time from a time server and it has received the time, it knows the total elapsed time that the request took. It does not know how long the request took to reach the time server and it does not know how long the response took to get from the server to the requesting computer. The elapsed time between when a request reaches a server and when the response leaves the server is usually very small. For practical purposes, the time that it takes for the response to travel from the server to the requesting computer is the inaccuracy of the response when it reaches the requesting computer. A reasonable way to estimate this time is to assume that the time it takes the request to travel from the requesting computer to the server is equal to the time it takes the response to travel from the server to the requesting computer. This makes our estimate of the time it takes for the response to get to the requesting computer one half of the elapsed time between when the request was issued and the response was received. 350 ■ CHAPTER EIGHT TEAMFLY Team-Fly ® When the requesting computer receives the current time from a time server, it adds one half of the elapsed time to the time it receives and uses that as the actual current time. CONSEQUENCES ⁄ Given events recorded by different computers, the Time Server pat- tern allows the times at which those events occurred to be accurately compared. Ÿ If the time server becomes unavailable for a long period of time, a distributed application that relies on the clocks of multiple comput- ers being synchronized may fail. This situation can generally be avoided by using multiple time servers, as is discussed under the fol- lowing “Implementation” heading. IMPLEMENTATION The Time Server pattern is most often implemented at the system level rather than at the application level. If the computers in question are general- purpose computers that run multiple applications, then implementing the Time Server pattern at the system level allows all applications that run on the computer to share the benefits of a single implementation of the Time Server pattern. In some cases, it is not possible for a distributed application to assume that the time clocks of the computers it runs on are synchronized. In that case, the application must have an application-level implementa- tion of the Time Server pattern. By using multiple time servers, you can minimize the effects of erratic network speeds and greatly increase the availability of the current time service. Computing the current time by averaging the adjusted results from multiple time servers minimizes the effects of erratic network speeds. Using multiple time servers ensures that the failure of a single time server does not make the current time unavailable. If the Time Server pattern is implemented at the application level, it will generally not be possible for the class that implements the pattern to set the system clock. Instead, the class can keep track of the difference between the local system time and the time server’s time. By making the time client class the source of the current time for the rest of the applica- tion, the time client class can achieve the same effect by applying the dif- ference between the local and server time to the system time before returning it. The shortcoming to this approach is that if the local clock is Temporal Patterns ■ 351 [...]... previous state, distinguishing between them by the time intervals when each state is valid Every time the state of a business object is fetched, it must happen in the context of a point in time Figure 8. 2 shows this design In this design, the state of a BusinessObject is extrinsic Its state does not reside in the BusinessObject instance itself, but in associated instances of BusinessObjectState The... for (int i=0; i0) { // Adjust position in array Interval tmpInterval = intervals[i]; intervals[i] = intervals[i-1]; intervals[i-1]... this IntervalMap */ private int getLatestIndex() { if (length==0) { throw new NoSuchElementException(); } // if int latestIndex = 0; Interval latestInterval = intervals[latestIndex]; for (int i=1; i . does not reside in the BusinessObject instance itself, but in associated instances of BusinessObjectState. The only attributes of BusinessObject that are intrinsic (reside within instances of the. time the state of a business object is fetched, it must happen in the context of a point in time. Figure 8. 2 shows this design. In this design, the state of a BusinessObject is extrinsic. Its state. timekeeping terminals to indicate the beginning of a shift and the end of a shift. When a timekeeping terminal reports a timekeeping event, the time of the event is determined by the timekeeping

Ngày đăng: 14/08/2014, 02:20

TỪ KHÓA LIÊN QUAN