AOP concurrency
For many developers, concurrency remains a mystery.
Concurrency is the system's ability to act with several requests simultaneously,
such a way that threads don't corrupt the state of objects when they gain
access at the same time.
A number of good books have been written on this subject, such as Concurrent
Programming in Java and Java Concurrency in Practice. They deserve much
attention, since concurrency is an aspect that's hard to understand, and not
immediately visible to developers. Problems in the area of concurrency are hard
to reproduce. However, it's important to keep concurrency in mind to assure
that the application is robust regardless of the number of users it will serve.
If we don't take into account concurrency and document when and how the problems
of concurrency are considered, we will build an application taking some risks
by supposing that the CPU will never simultaneously schedule processes on parts
of our application that are not thread-safe.
To ensure the building of robust and scalable systems, we use proper patterns.
There are JDK packages just for concurrency. They are in the
java.util.concurrent package, a result of JSR-166.
One of these patterns is the read-write lock pattern, which consists of is the
interface java.util.concurrent.locks.ReadWriteLock and some implementations,
one of which is ReentrantReadWriteLock.
The goal of ReadWriteLock is to allow the reading of an object from a virtually
endless number of threads, while only one thread at a time can modify it. In
this way, the state of the object can never be corrupted because threads
reading the object's state will always read up-to-date data, and the thread
modifying the state of the object in question will be able to act without the
possibility of the object's state being corrupted. Another necessary feature is
that the result of a thread's action can be visible to the other threads. The
behavior is the same as we could have achieved using synchronized, but when
using a read-write lock we are explicitly synchronizing the actions, whereas
with synchronized synchronization is implicit.
Now let's see an example of ReadWriteLock on the BankAccountThreadSafe object.
Before the read operation that needs to be safe, we set the read lock. After the
read operation, we release the read lock.
Before the write operation that needs to be safe, we set the write lock. After a
state modifi cation, we release the write lock.
package org.springaop.chapter.five.concurrent;
import java.util.Date;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public final class BankAccountThreadSafe {
public BankAccountThreadSafe(Integer
id) {
this.id = id;
balance
= new Float(0);
startDate
= new Date();
}
public BankAccountThreadSafe(Integer
id, Float balance) {
this.id = id;
this.balance = balance;
startDate = new Date();
}
public
BankAccountThreadSafe(Integer id, Float balance, Date start)
{
this.id = id;
this.balance = balance;
this.startDate = start;
}
public boolean
debitOperation(Float debit) {
wLock.lock();
try {
float balance = getBalance();
if (balance < debit) {
return false;
} else {
setBalance(balance - debit);
return true;
}
} finally {
wLock.unlock();
}
}
public void
creditOperation(Float credit) {
wLock.lock();
try {
setBalance(getBalance() + credit);
}
finally {
wLock.unlock();
}
}
private void
setBalance(Float balance) {
wLock.lock();
try
{
balance = balance;
} finally {
wLock.unlock();
}
}
public Float
getBalance() {
rLock.lock();
try
{
return balance;
} finally {
rLock.unlock();
}
}
public
Integer getId() {
return id;
}
public
Date getStartDate() {
return (Date) startDate.clone();
}
private Float balance;
private final Integer id;
private final Date startDate;
private final ReadWriteLock lock = new
ReentrantReadWriteLock();
private final Lock rLock = lock.readLock();
private final Lock wLock = lock.writeLock();
}
BankAccountThreadSafe is a class that doesn't allow a bank account to be
overdrawn (that is, have a negative balance), and it's an example of a
thread-safe class. The final fi elds are set in the constructors, hence
implicitly thread-safe. The balance fi eld, on the other hand, is managed in a
thread-safe way by the setBalance, getBalance, creditOperation, and
debitOperation methods.
In other words, this class is correctly programmed, concurrency-wise. The
problem is that wherever we would like to have those characteristics, we have
to write the same code (especially the finally block containing the lock's
release).
We can solve that by writing an aspect that carries out that task for us.
-
A state modifi cation is execution(void com.mycompany.BankAccount.set*(*))
-
A safe read is execution(* com.mycompany.BankAccount.getBalance())
package org.springaop.chapter.five.concurrent;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class BankAccountAspect {
/*pointcuts*/
@Pointcut(
"execution(* org.springaop.chapter.five.concurrent.BankAccount.
getBalance())")
public void safeRead(){}
@Pointcut(
"execution(*
org.springaop.chapter.five.concurrent.BankAccount.
set*(*))")
public void stateModification(){}
@Pointcut(
"execution(* org.springaop.chapter.five.concurrent.BankAccount. getId())")
public void getId(){}
@Pointcut("execution(* org.springaop.chapter.five.concurrent.
BankAccount.getStartDate()))
public void getStartDate(){}
/*advices*/
@Before("safeRead()")
public void beforeSafeRead() {
rLock.lock();
}
@After("safeRead()")
public void afterSafeRead() {
rLock.unlock();
}
@Before("stateModification()")
public void beforeSafeWrite() {
wLock.lock();
}
@After("stateModification()")
public void afterSafeWrite() {
wLock.unlock();
}
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock rLock = lock.readLock();
private final Lock wLock = lock.writeLock();
}
The BankAccountAspect class applies the crosscutting functionality. In this
case, the functionality is calling the lock and unlock methods on the ReadLock
and the WriteLock. The before methods apply the locks with the @Before
annotation, while the after methods release the locks as if they were in the fi
nal block, with the @After annotation that is always executed (an after-fi
nally advice).
In this way the BankAccount class can become much easier, clearer, and briefer.
It doesn't need any indication that it can be executed in a thread-safe manner.
package org.springaop.chapter.five.concurrent;
import java.util.Date;
public class BankAccount {
public BankAccount(Integer id) {
this.id = id;
this.balance = new
Float(0);
this.startDate = new
Date();
}
public BankAccount(Integer id, Float balance) {
this.id = id;
this.balance = balance;
this.startDate = new
Date();
}
public BankAccount(Integer id, Float balance, Date start) {
this.id = id;
this.balance = balance;
this.startDate = start;
}
public boolean debitOperation(Float debit) {
float balance = getBalance();
if (balance < debit) {
return false;
} else {
setBalance(balance - debit);
return true;
}
}
public void creditOperation(Float credit) {
setBalance(getBalance() + credit);
}
private void setBalance(Float balance) {
this.balance = balance;
}
public Float getBalance() {
return balance;
}
public Integer getId() {
return id;
}
public Date getStartDate() {
return (Date) startDate.clone();
}
private Float balance;
private final Integer id;
private final Date startDate;
}
Another good design choice, together with the use of ReadWriteLock when
necessary, is using objects that once built are immutable, and therefore, not
corruptible and can be easily shared between threads.
Also read
Explain the concepts and capabilities of Aspect-Oriented Programming, AOP.
What is Aspect in AOP?
AOP approach addresses Crosscutting concerns. Explain
The components of AOP are advices/interceptors, introductions, metadata, and
pointcuts. Explain them
AOP vs OOPs...........
What is the relation between Classes and Objects? Explain different properties
of Object Oriented Systems. What is difference between Association, Aggregation
and Inheritance relationships? Explain the features of an abstract class in
NET. Difference between abstract classes and interfaces Similarities and
difference between Class and structure in .NET Features of Static/Shared
classes. What is Operator Overloading in .NET?.............
What
is object oriented programming (OOP)?
The object oriented programming is commonly known as OOP. Most of the languages
are developed using OOP concept. Object-oriented programming (OOP) is a
programming concept that uses "objects" to develop a system.........
What
are the various elements of OOP?
Various elements of OOP are.........
Explain
an object, class and Method.
An object is an entity that keeps together state and behaviors.
For instance, a car encapsulates state such as red color, 900 cc etc and
behaviors as 'Start', 'Stop' etc., so does an object...............
|