Hi!!
It seems that the ReentrantLock is not working. I have been working around this little example and something is missing here. I made this little test application that simulate a transaction concurrent scenario over an account. As I a can see, there is a error on the lock because if you run it, and you wait for a while you will see that the account balance is going to have a negative balance. This shouldn't happen if the lock were made.
I hope I have made a mistake.
this is the code.
public class TestMain {
public static void main(String[] args) {
final ArrayBlockingQueue<Long> queue = new ArrayBlockingQueue<Long>(10);
int nThreads = Integer.parseInt(args[0]);
for (int i = 0; i < nThreads; i++)
new BankSystem(queue);
for (int i = 0; i < 20; i++)
new Thread(new WithdrawRequests(queue)).start();
for (int i = 0; i < 10; i++)
new Thread(new DepositRequests(queue)).start();
}
}
public class BankSystem implements Runnable {
private Thread tread;
private BlockingQueue<Long> queue;
private ProcessOperation processOperation = new ProcessOperation();
public BankSystem(BlockingQueue<Long> q) {
queue = q;
tread = new Thread(this);
tread.start();
}
public void run() {
long request, result;
try {
while (true) {
request = queue.take().longValue();
result = processOperation.process(request);
System.out.println("Calculated result of " + result + " from " + request);
}
} catch (InterruptedException ex) {
}
}
}
public class ProcessOperation {
private Account account = new Account(200);
public long process(long request) {
return account.transfer(request);
}
}
public class Account {
private final ReentrantLock lock = new ReentrantLock(true);
private static long balance = 0;
public Account(long initialBalance) {
this.balance = initialBalance;
}
// synchronized
public long transfer(long amount) {
lock.lock();
try {
if ((balance < 0) || (balance > 40000))
System.out.println("ERROR!!! (" + balance + ")");
if ((balance + amount) < 0)
return balance;
return balance += amount;
} finally {
lock.unlock();
}
}
public long getBalance() {
return balance;
}
}
public class WithdrawRequests implements Runnable {
private Thread thread;
private BlockingQueue<Long> queue;
public WithdrawRequests(BlockingQueue<Long> q) {
queue = q;
thread = new Thread(this);
thread.start();
}
public void run() {
try {
Random randomGenerator = new Random();
while (true) {
int amount = randomGenerator.nextInt(300);
queue.put(new Long(amount*-1));
Thread.yield();
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
public class DepositRequests implements Runnable {
private Thread tread;
private BlockingQueue queue;
public DepositRequests(BlockingQueue<Long> q) {
queue = q;
tread = new Thread(this);
tread.start();
}
public void run() {
try {
Random randomGenerator = new Random();
while (true) {
int amount = randomGenerator.nextInt(100);
queue.put(new Long(amount));
Thread.yield();
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
However, if you make the transfer method of the Account class "synchronized", you will not have an error on the account balance.
Do you have any idea?
Cheers!!