Parallel programming has long ceased to be the lot of experienced gurus. It is hard to imagine a modern application, the implementation of which would ignore this question. Similarly, it is difficult to imagine an application programmer who would not be armed with corporate application patterns from Fowler with the company. Actually about the features inherent in these patterns and will be discussed in this post. The material presented below almost does not correlate with the implementation technologies, so it may be of interest to any application programmers, despite the fact that the examples are based on Java and PostgreSQL. And one more note, in order not to confuse the names of the patterns, I will use their original names in English.
Behavior of implementations of Offline Lock patterns at different levels of simultaneous access [Optimistic Offline Lock, Pessimistic Offline Lock]
This section discusses the behavior at different levels of simultaneous access for two types of control, optimistic and pessimistic, based on the implementations of Offline Lock patterns. Behavior will be reviewed based on synthetic performance test results. Actually, performance is not always a problem for software. It all depends on the specific situation. For example, in a system where the speed of operations is limited by the speed of user input, it is unlikely that problems will arise with insufficient performance of these operations. Conversely, in a system where the speed of operations is limited only by the capabilities of the hardware and the implementation, insufficient performance can be a big problem.
Let us proceed to measuring the performance of optimistic and pessimistic simultaneous access control for the implementation of Optimistic Offline Lock and Pessimistic Offline Lock patterns at different levels of parallel access. For this measurement, you will need a table with data on which we will receive test results. Scheme of the table and test data are presented below:
')
CREATE TABLE values ( "id" integer PRIMARY KEY, "field1" varchar(4096), "field2" decimal(20, 2), "locked" boolean, "version" integer DEFAULT 0 ); INSERT INTO values ( "id", "field1", "field2", "locked", "version" ) VALUES ( 1,'record 1', 0.00, false, 0 );
Consider the implementation of a test application based on which measurements will be taken. The implementation uses the Spring Framework and Hibernate technologies, which are among the most common Java in the world. Using the data framework made it possible to make the test code as concise and understandable as possible. First, consider the entity class (reflects the row in the values ​​table):
@Entity @Table(name="values", schema="public") public class Value { @Id private Integer id; private String field1; private BigDecimal field2; private Boolean locked; private Integer version;
The implementation of each of the Offline Lock patterns consists of two DAO and Task classes. The DAO implements all the logic for accessing the database and checking locks. In Task, the code for changing data based on the type of control of simultaneous access control and a specific code to ensure testing. Note 1: Pessimistic Offline Lock is implemented without using the Lock Manager pattern in order to ensure maximum similarity between the implementations of the two patterns (Pessimsitic and Optimistic). Note 2: when implementing the Optimistic Offline Lock pattern, manual version control was used, again for reasons of similarity, it is preferable to use the built-in Hibernate mechanism in a real application.
Optimistic Offline Lock Implementation Code
@Repository("optimisticDao") @Scope("prototype") public class ValueDaoWithOptimisticControl implements ValueDao {
Pessimsitic Offline Lock Implementation Code
@Repository("pessimisticDao") @Scope("prototype") public class ValueDaoWithPessimisticControl implements ValueDao {
Anyone who is interested in the full test code can download the
archive and experiment on their own. To build the project, maven 3 is used. The test can be launched by the following commands from the project directory:
export MAVEN_OPTS=-server mvn exec:java -Dexec.mainClass="concurrency.patterns.Application" \ -Dexec.args="-time ___ \ -concurrency_rate _ -id _ -action _"
The results of tests with different levels of simultaneous access (given for the interval of 10 seconds) are presented in the graph below. Measurements were made on 4 nuclear cpu.

Frankly, for me this result was a little unexpected. I was counting on a much lower degree of degradation of Pessimistic Offline Lock. According to the results, it is clear that both approaches have a comparable level of degradation. When I first implemented the test, due to an oversight, I loaded data in the ValueDaoWithOptimisticControl class with a lock pickup, which led to a much greater degradation of the Optimistic Offline Lock implementation. In the final implementation, Pessimistic Offline Lock has a steeper decline due to a greater number of queries to the database to perform an action. With a pessimistic form of simultaneous access control, 4 queries to the database are executed (2 select for update and 2 update set and unlock), with optimistic 3 queries (1 select, 2 select for update and update). Actually, the whole difference in performance is caused by the difference in requests, because it is on them that the main execution time is spent. In fact, both approaches provide a serialization of performing an action on a row in a database, and therefore the final result is approximately equal to the test execution time divided by the execution time of one action. The main difference in behavior is to perform an action without a guarantee that the result will be saved. In other words, optional resource consumption. Such behavior is peculiar to an optimistic type of control. This is a fee for the absence of the need to release occupied resources upon abnormal termination.
The implementation of patterns presented above is not the most productive, squeezing more out of it can be reduced to loading and saving to two update requests for a pessimistic approach and to a select request with an update request for an optimistic one. This optimization will not be of fundamental importance in our context.
As a conclusion of this paragraph I want to highlight a few points. Firstly, the recommendation of Fouler regarding the choice of an optimistic approach wherever there are no problems with uselessly performed actions can be considered optimal. Secondly, both approaches provide a serialization of the execution of actions, which guarantees a similar degree of degradation with an increase in the level of simultaneous access. Ultimately, behavior is highly dependent on the implementation and execution context. Thirdly, it is necessary to clearly distinguish performance requirements in the application of Offline Lock patterns to control the simultaneous access of execution threads dependent on user input and without such dependence.
Captured resources on crash [Pessimistic Offline Lock]
A significant drawback of the Pessimistic Offline Lock pattern is the issue of captured resources in an emergency. Who and when should release the resources occupied by the abnormally terminated thread of execution. In the context of your application, these questions must be answered by any developer using the Pessimistic Offline Lock pattern.
Reset event locks
Obviously, in order to reset a lock whose owner disappeared without a trace, some kind of stimulus signal (event) is needed. Such an event may be for example: disconnection of a connection with a client, expiration of a temporary period of blocking retention, or simply the action of a user serving the system.
The approach of tracing the disconnection is applicable when the client and the application server interact through a protocol that supports the connection state. At what level support for the connection state will be implemented is not particularly important in this context. This can be either tracking a break in the tcp connection, or a state in the form of a web client session.
The time interval for holding the lock is a fairly straightforward way to solve the problem. When locking a lock, a timestamp is set which allows you to free resources with an elapsed blocking time. Despite such simplicity and this approach has its drawbacks. One of them is the need to find a compromise between a long time interval and the needs of customers who hold locks for a long time.
The two approaches described can be combined into a mixed form, where the state of the connection can be monitored by sending a signal by the client at a specified interval, or by updating the lock seizure time stamp.
Do not use a pessimistic approach
As it is not banal, but the problem with the release of resources can be solved simply by not occupying them. To control simultaneous access, you can use Optimistic Offline Lock, or you can completely abandon locks and update data on the basis of the latter, which erases all previous ones. But the second option is not universal and can only be used with certain classes of applications. In addition, non-blocking algorithms are very complex and have a high cost of support. The non-blocking approach should be resorted to as an exit with really reasonable performance requirements.
Using PaEAA Parallel Programming Patterns
Locking patterns are a means to control simultaneous access throughout a business transaction. A business transaction can be extended to several system transactions, which does not allow the use of DBMS synchronization mechanisms with the scope of a limited system transaction. In addition, long system transactions and long locks of locks contribute to problems with the availability of the database for maintenance. Performance issues in this case are not a problem, because they are more dependent on the policy of using locks, and not on specific implementation mechanisms.
The common purpose of parallel programming patterns PoEAA is to solve problems of simultaneous access at the business layer level. That is, the construction of a separate synchronization mechanism. In spite of this, for their correct implementation it is necessary to understand the low-level mechanisms that the DBMS provides: locks, transaction isolation.
Additional sources
Archive with the code of the test applicationPessimistic Offline LockOptimistic Offline Lock