I am writing a program in Java and I am a bit worried about synchronization.
The scenario is pretty "simple" we have a simple bank account class where multiple people can withdraw money from accounts (they can not deposit though) they can also check the balance of the account. The thing is that the balance changes all the time so we want the customers to view the correct balance!
Here is my class so far.
class Account implements Serializable {
private boolean available = false;
String ac_id;
String name;
int balance;
public Account(String ac_id, String name, int blnc)
{
this.ac_id = ac_id;
this.name = name;
this.blnc = blnc;
}
public synchronized int getMoney(int money) {
if (money > blnc) {
return -1;
}
while (available == true) {
try {
wait();
} catch (InterruptedException e) {
}
}
blnc -= money;
available = true;
notifyAll();
return 1;
}
public synchronized int chkBalance() {
return blnc;
}
#Override
public String toString()
{
return "Balance: " + chkBalance();
}
}
As you can see with this implementation I can ensure that someone can get money from one account object , but then this account object is blocked , then one solution is at
public synchronized int chkBalance()
method to add available = false; which seems to solve my problem, but I really cant say if this is correct, I mean if they are indeed synchronized and customers see the correct balance.
Thanks in advance!!
P.S. Theoretically, if I just used the synchronized word before each of these two methods, wouldn't be alright? I mean, only one thread would occupy each method at a time and since there is no need for deposits what is the point in using Boolean available true/false ?
You don't need available boolean at all. It's enough to synchronize only getMoney method and make blnc volatile so other threads checking for changes will be able to see them. Try something like:
class Account implements Serializable {
final String ac_id;
final String name;
volatile int blnc;
public Account(String ac_id, String name, int blnc) {
this.ac_id = ac_id;
this.name = name;
this.blnc = blnc;
}
public synchronized int getMoney(int money) {
if (money > blnc) {
return -1;
}
blnc -= money;
return 1;
}
public int chkBalance() {
return blnc;
}
#Override
public String toString() {
return "Balance: " + chkBalance();
}
}
If you are not concerned with the speed of execution, then all you need to do is make the methods synchronized. This will guarantee that each method of one particular account object is only accessed by one thread at a time. Your available flag doesn't appear useful in your implementation. There is also no point in putting wait() inside a synchronized method; this can only slow down other threads that are waiting for the object's lock.
It is particularly important that getMoney() be synchronized, because this method changes the value of blnc, and failing to synchronize it could result in two threads overwriting the value simultaneously, in which case one thread would fail to take effect.
In your implementation, it doesn't much matter if chkBalance() is synchronized because it does not write to blnc. If this method is called concurrently with getMoney(), it will either return the value of blnc before or after the change is made to blnc, and this scheduling is beyond programmer control.
It is also useful not to synchronize chkBalance() because you may have many simultaneous calls to chkBalance() from different threads, and there is no point in these calls waiting on each other.
To ensure that you are getting the latest value of blnc from shared memory, and not a locally cached value, consider making the blnc variable volatile.
... multiple people can withdraw money from accounts [and] they can also check the balance ...[but], the balance changes all the time so we want the customers to view the correct balance!
You can't. If other people (threads) can withdraw money at any time, then there is no such thing as the correct balance. The best you can guarantee is a correct balance. That is, with proper synchronization, you can ensure that the number returned by checkBalance() was correct at some point in the past.
Here's the problem. Some function fubar() calls checkBalance(). Why? Why does it care what the balance is? As soon as checkBalance() returns, the calling thread is no longer synchronized. Any other thread could potentially make a withdrawal between the time when checkBalance() returned, and the time when fubar() does something with the information.
If fubar() needs to know the balance in order to do something with the information, then fubar() needs to be synchronized too.
I think you are mixing things here :
getMoney is synchronized, so only 1 thread will get in at each time
when the available flag is true, you put the thread in wait, until someone calls notify (which you do yourself, in the same thread as it is synchronized)
Why are you mixing wait/notify and synchronized? Since the method is synchronized, no other thread will be in wait.. they will be blocking on the entry of the method.
To be honest, unless you add more logic to it, synchronization is not really usefull here : in your getMoney you only do an assignment to the balance. The chckBalance method is either executed just before, or just after... you never risk having dirty values anyway.
Related
I am trying to see how multithreading(particularly with synchronized keyword) works.In this example I want the second thread abc1 to start executing after thread abc. So I've used synchronized keyword in run function.But the output line which says:
Initial balance in this thread is 10000
Initial balance in this thread is 10000
is what concerns me.Because the initial balance should be "-243000" as indicated in output line
Final balance after intial -243000 is 59049000
because the abc1 thread should wait for abc due to synchronized keyword.
Primarily , I want the threads to behave as if I write
abc.start
abc.join()
abc1.start()
abc1.join()
Here is my source code:
class parallel extends Thread{
account a;
public parallel(account a) {
this.a=a;
}
public synchronized void run() {
synchronized(this) {
System.out.println("Initial balance in this thread is "+a.amount);
long duplicate=a.amount;
boolean flag=true;
//System.out.println("Transaction inititated");
for(int i=0;i<10;i++) {
if(flag==true) {
//System.out.println("Deducting "+amount+"Rs from your account");
a.amount-=a.amount*2;
}
else {
//System.out.println("Depositing "+amount+"Rs from your account");
a.amount+=a.amount*2;
}
flag=!flag;
}
System.out.println("Final balance after intial "+duplicate+" is "+a.amount);
syncro.amount=a.amount;
}
}
}
class account{
public account(long rupe) {
amount=rupe;
}
long amount;
}
public class syncro {
static long amount;
public static void main(String[] args) throws InterruptedException{
//for(int i=0;i<10;i++) {
account ramesh=new account(1000);
parallel abc=new parallel(ramesh);
parallel abc1=new parallel(ramesh);
abc.start();
//abc.join();
abc1.start();
//abc1.join();
//}
//awaitTermination();
//Thread.sleep(4000);
boolean ab=true;
long cd=1000;
for(int i=0;i<10;i++) {
if(ab==true) {
//System.out.println("Deducting "+ab+"Rs from your account");
cd-=cd*2;
}
else {
//System.out.println("Depositing "+a+"Rs from your account");
cd+=cd*2;
}
ab=!ab;
}
//System.out.println("Final amount by multithreading is "+);
System.out.println("Final amount after serial order is "+cd);
}
}
You are mixing the creating of your own threads with the use of synchronized. Also, using synchronized(this) within a synchronized method is doing the same thing twice.
Synchronized is NOT about starting threads. It is about allowing only one thread to enter a certain block of code at a time.
Every object you create has a hidden field that you cannot read, but it does exist. It is of type Thread and it is called owner.
The synchronized keyword interacts with this hidden field.
synchronized (object) {
code();
}
means the following:
If object.owner == Thread.currentThread(), then just keep going and increment a counter.
If object.owner == null, then run object.owner = Thread.currentThread(), set that counter to 1, and keep going.
Otherwise (So, object.owner is some other thread), stop, freeze the thread, and wait around until the owner is set to null, and then we can go to option #2 instead.
Once we're in, run code(). When we get to the closing brace, decrement the counter. If it is 0, run object.owner = null.
Furthermore, all the above is done atomically - it is not possible for 2 threads to get into a race condition doing all this stuff. For example, if 2 threads are waiting for owner to become unset again, only one will 'get it', and the other will continue waiting. (Which one gets it? A VM impl is free to choose whatever it wants; you should assume it is arbitrary but unfair. Don't write code that depends on a certain choice, in other words).
A method that is keyworded with synchronized is just syntax sugar for wrapping ALL the code inside it in synchronized(this) for instance methods and synchronized(MyClass.this) for static methods.
Note that synchronized therefore only interacts with other synchronized blocks, and only those blocks for which the object in the parentheses is the exact same obj reference, otherwise none of this does anything. It certainly doesn't start threads! All synchronized does is potentially pause threads.
In your code, you've put ALL the run code in one gigantic synchronized block, synchronizing on your thread instance. As a general rule, when you synchronize on anything, it's public API - other code can synchronize on the same thing and affect you. Just like we don't generally write public fields in java, you should not lock on public things, and this is usually public (as in, code you don't control can hold a reference to you). So don't do that unless you're willing to spec out in your docs how your locking behaviours are set up. Instead, make an internal private final field, call it lock, and use that (private final Object lock = new Object();).
Good Day
I have a question relating ReentrantReadWriteLocks. I am trying to solve a problem where multiple reader threads should be able to operate in parallel on a data structure, while one writer thread can only operate alone (while no reader thread is active). I am implementing this with the ReentrantReadWriteLocks in Java, however from time measurement it seems that the reader threads are locking each other out aswell. I don't think this is supposed to happen, so I am wondering if I implemented it wrong. The way I implemented it is as follows:
readingMethod(){
lock.readLock().lock();
do reading ...
lock.readLock().unlock();
}
writingMethod(){
lock.writeLock().lock();
do writing ...
lock.writeLock().unlock();
}
Where the reading method is called by many different threads. From measuring the time, the reading method is being executed sequentially, even if the writing method is never invoked! Any Idea on what is going wrong here? Thank you in advance -Cheers
EDIT: I tried to come up with a SSCCE, I hope this is clear:
public class Bank {
private Int[] accounts;
public ReadWriteLock lock = new ReentrantReadWriteLock();
// Multiple Threads are doing transactions.
public void transfer(int from, int to, int amount){
lock.readLock().lock(); // Locking read.
// Consider this the do-reading.
synchronized(accounts[from]){
accounts[from] -= amount;
}
synchronized(accounts[to]){
accounts[to] += amount;
}
lock.readLock().unlock(); // Unlocking read.
}
// Only one thread does summation.
public int totalMoney(){
lock.writeLock().lock; // Locking write.
// Consider this the do-writing.
int sum = 0;
for(int i = 0; i < accounts.length; i++){
synchronized(accounts[i]){
sum += accounts[i];
}
}
lock.writeLock().unlock; // Unlocking write.
return sum;
}}
I know the parts inside the read-Lock are not actually reads but writes. I did it this way because there are multiple threads performing writes, while only one thread performs reads, but while reading, no changes can be made to the array. This works in my understanding. And again, the code inside the read-Locks works fine with multiple threads, as long as no write method and no read-locks are added.
Your code is so horribly broken that you should not worry about any performance implication. Your code is not thread safe. Never synchronize on a mutable variable!
synchronized(accounts[from]){
accounts[from] -= amount;
}
This code does the following:
read the contents of the array accounts at position from without any synchronization, thus possibly reading a hopelessly outdated value, or a value just being written by a thread still inside its synchronized block
lock on whatever object it has read (keep in mind that the identity of Integer objects created by auto-boxing is unspecified [except for the -128 to +127 range])
read again the contents of the array accounts at position from
subtract amount from its int value, auto-box the result (yielding a different object in most cases)
store the new object in array accounts at position from
This implies that different threads can write to the same array position concurrently while having a lock on different Integer instances found on their first (unsynchronized) read, opening the possibility of data races.
It also implies that threads may block each other on different array positions if these positions happen to have the same value happened to be represented by the same instance. E.g. pre-initializing the array with zero values (or all to the same value within the range -128 to +127) is a good recipe for getting close to single thread performance as zero (or these other small values) is one of the few Integer values being guaranteed to be represented by the same instance. Since you didn’t experience NullPointerExceptions, you obviously have pre-initialized the array with something.
To summarize, synchronized works on object instances, not variables. That’s why it won’t compile when trying to do it on int variables. Since synchronizing on different objects is like not having any synchronization at all, you should never synchronize on mutable variables.
If you want thread-safe, concurrent access to the different accounts, you may use AtomicIntegers. Such a solution will use exactly one AtomicInteger instance per account which will never change. Only its balance value will be updated using its thread-safe methods.
public class Bank {
private final AtomicInteger[] accounts;
public final ReadWriteLock lock = new ReentrantReadWriteLock();
Bank(int numAccounts) {
// initialize, keep in mind that this array MUST NOT change
accounts=new AtomicInteger[numAccounts];
for(int i=0; i<numAccounts; i++) accounts[i]=new AtomicInteger();
}
// Multiple Threads are doing transactions.
public void transfer(int from, int to, int amount){
final Lock sharedLock = lock.readLock();
sharedLock.lock();
try {
accounts[from].addAndGet(-amount);
accounts[to ].addAndGet(+amount);
}
finally {
sharedLock.unlock();
}
}
// Only one thread does summation.
public int totalMoney(){
int sum = 0;
final Lock exclusiveLock = lock.writeLock();
exclusiveLock.lock();
try {
for(AtomicInteger account: accounts)
sum += account.get();
}
finally {
exclusiveLock.unlock();
}
return sum;
}
}
For completeness, as I guess this question will arise, here is how a withdraw process forbidding taking more money than available may look like:
static void safeWithdraw(AtomicInteger account, int amount) {
for(;;) {
int current=account.get();
if(amount>current) throw new IllegalStateException();
if(account.compareAndSet(current, current-amount)) return;
}
}
It may be included by replacing the line accounts[from].addAndGet(-amount); by safeWithdraw(accounts[from], amount);.
Well after writing the example above, I remembered that there is the class AtomicIntegerArray which fits even better to this kind of task…
private final AtomicIntegerArray accounts;
public final ReadWriteLock lock = new ReentrantReadWriteLock();
Bank(int numAccounts) {
accounts=new AtomicIntegerArray(numAccounts);
}
// Multiple Threads are doing transactions.
public void transfer(int from, int to, int amount){
final Lock sharedLock = lock.readLock();
sharedLock.lock();
try {
accounts.addAndGet(from, -amount);
accounts.addAndGet(to, +amount);
}
finally {
sharedLock.unlock();
}
}
// Only one thread does summation.
public int totalMoney(){
int sum = 0;
final Lock exclusiveLock = lock.writeLock();
exclusiveLock.lock();
try {
for(int ix=0, num=accounts.length(); ix<num; ix++)
sum += accounts.get(ix);
}
finally {
exclusiveLock.unlock();
}
return sum;
}
You can run 2 threads on this test
static ReadWriteLock l = new ReentrantReadWriteLock();
static void readMehod() {
l.readLock().lock();
System.out.println(Thread.currentThread() + " entered");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
l.readLock().unlock();
System.out.println(Thread.currentThread() + " exited");
}
and see if both threads enter the readlock.
I am doing some personal research for examinations. Past exams have asked Outline how a partially initialised object in Java is vulnerable to exploitation. and also, What are the possible complications of somebody exploiting said Objects in your application
Now, i found this resource here: securecoding.cert
On the above website, i can see examples as to how its done, but i can't seem to see or understand the purpose of it, what can you actually maliciously do with such Objects.
From what i understand, you should always check that Object instantiation has completed when performing operations (e.g. Boolean or similar) like so;
class BankAccount {
private int balance; // Defaults to 0
private volatile boolean initialized = false;
public BankAccount() {
if (!performAccountVerification()) {
throw new SecurityException("Invalid Account");
}
balance = 1000;
// ...
initialized = true;
}
public int getBalance() {
if (!initialized) {
throw new IllegalStateException("Class not initialized");
}
return balance;
}
// ...
}
Code taken from the above resource.
You should also use volatile, as you want to ensure synchronisation because part of the problem is the fact that the Java Memory allows other Threads to access these Partially Initialised Objects.
So in summary:
Why would you want to do this?
What can you actually do with these Objects
Should you always be concerned about this, or only in critical systems?
Thanks,
Chris.
Well, if I don't have access to a bank account, and your class isn't checking that initialized flag, I could theoretically be able to do something like this:
class Thief extends Thread {
public BankAccount ba = null;
void run() {
do {
if(ba != null) ba.transferAllMoneyToDima();
} while(ba == null);
}
}
Thief th = new Thief();
th.start();
th.ba = new BankAccount();
What happens here is that BankAccount constructor is supposed to verify that I have access to the account, and throw an exception if not. By optimizer is allowed to reorder certain operations. In particular, it can assign the object to th.ba immediately after it is allocated, before the constructor completes. If that happens, my Thief thread will see the non-null value, and steal of the money before the vertification completes and determines that I should not have been allowed to do this.
I am having a very hard time trying to understand the concept of synchronizing methods, objects and understand the main issue of not doing so, when running a multi-threaded application.
I understand that synchronize keyword is used to make sure that only one thread will work with a specific object or enter a specific block or method in a time, basically locks it and unlocks when the execution ended, so the other threads can enter it.
But I don't really understand the problem, I am totally confused, I created a demo application, where I have 2 bank accounts, and one bank class which has 5000 funds and a method that transfers a specific amount of money to the given account, and in it's constructor it creates the 2 bank accounts and start the threads (each account is a thread).
Now in the bank account's class I have a funds field, and a run method which the thread will call upon start (the class inheriting Thread), and the run method will loop 10 times, and take 20 dollar from the main bank by calling Bank#takeFunds(int amount)
So there we go, the Bank class:
public class Bank {
private int bankmoney = 5000;
public Bank() {
Client a = new Client(this);
Client b = new Client(this);
a.start();
b.start();
}
public void takeMoney(Client c, int amount) {
if (bankmoney >= amount) {
bankmoney -= amount;
c.addFunds(amount);
}
}
public void print() {
System.out.println("left: " + bankmoney);
}
public static void main(String... args) {
new Bank();
}
}
And the Client class:
public class Client extends Thread {
private Bank b;
private int funds;
Random r = new Random();
public Client(Bank b) {
this.b = b;
}
public void addFunds(int funds) {
this.funds += funds;
}
public void run() {
for (int i = 0; i < 10; i++) {
b.takeMoney(this, 20);
}
System.out.println(Thread.currentThread().getName() + " : " + funds);
b.print();
}
}
And the output for me:
Thread-0 : 200
left: 4800
Thread-1 : 200
left: 4600
The program ends with 200$ in each account, and 4600 left in the bank, so I don't really see the issue, I am failing to demonstrate the issue of thread safety, and I think this is why I can't understand it.
I am trying to get the most simple explanation on how it works exactly, How can my code turn into a problem with thread safety?
Thanks!
Example:
static void transfer(Client c, Client c1, int amount) {
c.addFunds(-amount);
c1.addFunds(amount);
}
public static void main(String... args) {
final Client[] clients = new Client[]{new Client(), new Client()};
ExecutorService s = Executors.newFixedThreadPool(15);
for (int i = 0; i < 15; i++) {
s.submit(new Runnable() {
#Override
public void run() {
transfer(clients[0], clients[1], 200);
}
});
}
s.shutdown();
while(!s.isTerminated()) {
Thread.yield();
}
for (Client c : clients) {
c.printFunds();
}
}
Prints:
My funds: 2000
My funds: 8000
To start with, a thread is not an object. Do not assign a separate thread to each client. Threads do work and objects contain code which specifies what must be done.
When you call methods on a Client object, they do not execute "on that client's thread"; they execute in the thread from which they are called.
In order to make a thread do some work, you need to hand it over an object implementing the code to be executed on it. That's what an ExecutorService allows you to do simply.
Also keep in mind that locks do not "lock objects" and synchronized(anObject) will not on its own stop another thread from calling anObject's methods at the same time. Locks only prevent other threads trying to acquire the same lock from proceeding until the first thread is done with it.
I tested your program, and in fact got the following output:
(The result is not 4600 as in your case.)
The point is that just because it happens to work once doesn't mean that it will always work. Multi threading can (in an illsynchronized program) introduce non-determinism.
Imagine what would happen if your operations took a bit longer to execute. Let's simulate this with a Thread.sleep:
public void takeMoney(Client c, int amount) {
if (bankmoney >= amount) {
try { Thread.sleep(1000); } catch (InterruptedException e) { }
bankmoney -= amount;
c.addFunds(amount);
}
}
Now try running your program again.
your program is working fine , as you are only deducting total amount of 2000. Which is far lesser than initial value. So, this check has no play, you code will work even if you rmeove it.
if (bankmoney >= amount) {
The only bad thing that can happen in this scenario , if client1 checks that amount is more than he needs to withdraw , but in meantime other client withdraws it.
public void run() {
for (int i = 0; i < 100; i++) {
b.takeMoney(this, 200);
}
System.out.println(Thread.currentThread().getName() + " : " + funds);
b.print();
}
public void takeMoney(Client c, int amount) {
if (bankmoney >= amount) {
system.println("it is safer to withdraw as i have sufficient balance")
bankmoney -= amount;
c.addFunds(amount);
}
}
there will be time when client one will check bankmoney is greater than amount , but when he withdraws, it will reach to negative amount. as other thread will take that amount.
Run program, 4-5 times you will realize.
Let's look at a more realistic example and implement a transfer function for our Bank:
public boolean transfer(long amount, Client source, Client recipient) {
if(!source.mayTransferAmount(amount)) return false; // left as an exercise
source.balance -= amount;
recipient.balance += amount;
}
Now let's imagine two threads. Thread A transfers a single unit from Client x to Client y while Thread B transfers a single unit from Client y to Client x. Now you must know that without synchronization, you cannot be sure how the CPU orders operations, so it could be:
A: get x.balance (=100) to tmpXBalance
B: get x.balance (=100) to tmpXBalance
B: increment tmpXBalance (=101)
B: store tmpXBalance to x.balance (=101)
A: decrement tmpXBalance (=99)
A: store tmpXBalance to x.balance (=99)
(rest of exchange omitted for brevity)
Whoa! We just lost money! Client x won't be very happy. Note that locking alone won't give you any guarantee, you also need to declare balance as volatile.
Any time there's something you want to do to data that are shared by more than one thread, if it takes more than one step, then you probably need synchronization.
This takes three steps:
i++;
The steps are; (1) get the value of i from memory into a register, (2) add 1 to the register, (3) store the value of the register back into memory.
A running thread can be preempted at any time. That means, the operating system can pause it, and give some other thread a turn using the CPU. So, if there's no synchronization, thread A could perform step (1) of incrementing i (it could get the value into a register), and then it could be preempted. While thread A is waiting to run again, threads B, C, and D could each increment i a thousand times. Then when thread A finally got to run again, it would add 1 to the value that it originally read, and then store that back into memory. The three thousand increments by threads B, C, and D would be lost.
You need synchronization whenever one thread could put some data into a temporary state that you don't want other threads to see or operate on. The code that creates the temporary state must be synchronized, and any other code that could operate on the same data must be synchronized, and any code that merely allows a thread to see the state must synchronized.
As Marko Topolnik pointed out, synchronization doesn't operate on data, and it doesn't operate on methods. You need to make sure that all of the code that modifies or looks at a particular collection of data is synchronized on the same object. That's because synchronization does one thing, and one thing only:
The JVM will not allow two threads to be synchronized on the same object at the same time. That's all it does. How you use that is up to you.
If your data are in a container, it may be convenient for you to synchronize on the container object.
If your data are all instance variables of the same Foobar instance, then it may be convenient for you to synchronize on the instance.
If your data are all static, then you probably should synchronize on some static object.
Good luck, and have fun.
I have a Bank class with a list of Account. The bank has a transfer() method to transfer a value from one account to another. The idea is to lock both the from and to accounts within a transfer.
To solve this issue I have the following code (please bear in mind that this is a very trivial example because it's just that, an example):
public class Account {
private int mBalance;
public Account() {
mBalance = 0;
}
public void withdraw(int value) {
mBalance -= value;
}
public void deposit(int value) {
mBalance += value;
}
}
public class Bank {
private List<Account> mAccounts;
private int mSlots;
public Bank(int slots) {
mAccounts = new ArrayList<Account>(Collections.nCopies(slots, new Account()));
mSlots = slots;
}
public void transfer(int fromId, int toId, int value) {
synchronized(mAccounts.get(fromId, toId)) {
synchronized(mAccounts.get(toId)) {
mAccounts.get(fromId).withdraw(value);
mAccounts.get(toId).deposit(value);
}
}
}
}
This works, but does not prevent deadlocks. To fix that, we need to change the synchronization to the following:
synchronized(mAccounts.get(Math.min(fromId, toId))) {
synchronized(mAccounts.get(Math.max(fromId, toId))) {
mAccounts.get(fromId).withdraw(value);
mAccounts.get(toId).deposit(value);
}
}
But the compiler warns me about nested synchronization blocks and I trust that that is a bad thing to do? Also, I'm not very fond of the max/min solution (I was not the one who came up with that idea) and I would like to avoid that if possible.
How would one fix those 2 problems above? If we could lock on more than one object, we would lock both the from and to account, but we can't do that (as far as I know). What's the solution then?
I personally prefer to avoid any but the most trivial synchronization scenario. In a case like yours I would probably use a synchronized queue collection to funnel deposits and withdraws into a single-threaded process that manipulates your unprotected variable. The "Fun" thing about these queues is when you put all the code into the object that you drop into the queue so the code pulling the object from the queue is absolutely trivial and generic (commandQueue.getNext().execute();)--yet the code being executed can be arbitrarily flexible or complex because it has an entire "Command" object for it's implementation--this is the kind of pattern that OO-style programming excels at.
This is a great general-purpose solution and can solve quite a few threading problems without explicit synchronization (synchronization still exists inside your queue but is usually minimal and deadlock-free, often only the "put" method needs to be synchronized at all, and that's internal).
Another solution to some threading problems is to ensure that every shared variable you might possibly write to can only be "Written" to by a single process, then you can generally leave off synchronization altogether (although you may need to scatter a few transients around)
Lock ordering is indeed the solution, so you're right. The compiler warns you because it cannot make sure all your locking is ordered—it's not smart enough to check your code, and smart enough to know there may be more.
An alternative solution could be locking on an enclosing object, e.g. for transfers within one user's account you could lock on user. Not so with transfers between users.
Having said that, you are not probably going to rely on Java locking in order to make a transfer: you need some data storage, usually a database. In case of using a database, the locking moves to the storage. Still, the same principles apply: you order locks to avoid deadlocks; you escalate locks to make locking simpler.
I would advise you to look into Lock Objects in java. Have a look at condition objects too. Each of your account object can expose a condition on which a thread waits. Once a transaction is complete, condition objects await or notify is called.
If you haven't already you may want to look at the more advanced locking packages in java.util.concurrent.
While you still have to take care to avoid with deadlock, the ReadWriteLocks in particular are useful to allow multi-thread read access while still locking for object modification.
Make this easy with Polyglot programming, use Software Transactional Memory with Clojure but in Java.
Software Transactional Memory (STM) is a concurrency control technique
analogous to database transactions for controlling access to shared
memory in concurrent computing. It is an alternative to lock based synchronization.
Example solution
Account.java
import clojure.lang.Ref;
public class Account {
private Ref mBalance;
public Account() {
mBalance = new Ref(0);
}
public void withdraw(int value) {
mBalance.set(getBalance() - value);
}
public void deposit(int value) {
mBalance.set(getBalance() + value);
}
private int getBalance() {
return (int) mBalance.deref();
}
}
Bank.java
import clojure.lang.LockingTransaction;
import java.util.*
import java.util.concurrent.Callable;
public class Bank {
private List<Account> mAccounts;
private int mSlots;
public Bank(int slots) {
mAccounts = new ArrayList<>(Collections.nCopies(slots, new Account()));
mSlots = slots;
}
public void transfer(int fromId, int toId, int value) {
try {
LockingTransaction.runInTransaction(
new Callable() {
#Override
public Object call() throws Exception {
mAccounts.get(fromId).withdraw(value);
mAccounts.get(toId).deposit(value);
return null;
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
Dependencies
<dependency>
<groupId>org.clojure</groupId>
<artifactId>clojure</artifactId>
<version>1.6.0</version>
</dependency>