Java Thread safety - Understanding the need of synchronization - java

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.

Related

synchronized keyword in Java threads

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();).

synchronized threads not blocking each other

I'm not trying to fill the board with another of the same question, but I read about 15 solutions and nobody has quite the same issue. Here is the code I am looking at:
private AgentModel agent;
private UserModel user;
private int type;
public AgentThread(AgentModel agent, UserModel user, int type) {
this.agent = agent;
this.user = user;
this.type = type;
}
public void start() throws InterruptedException {
agent.setT(new Thread(this, agent.getID()));
agent.getT().start();
}
And a little bit down the way:
public void run() {
while (!agent.getT().isInterrupted()) {
agent.nextOP();
try {
if (agent.getOPS() > 0) {
agent.getT().sleep((long) (1000 / agent.getOPS()));
} else {
agent.getT().sleep(1000);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
agent.getT().interrupt();
}
synchronized (user) {
agent.setState(agent.getT().getState().toString());
// System.out.println("Operations Completed: " +
// (1+agent.getOPCompleted()) );
if (type == 3) {
user.deposit(agent.getAmount(), Integer.valueOf(agent.getID()));
}
if (type == 4) {
user.withdraw(agent.getAmount(), Integer.valueOf(agent.getID()));
}
}
}
}
The agent object contains a thread that is started in the AgentThread start method. The AgentThread object takes in both the agent and the user and instances of their respective classes.
My problem is as follows: I'm setting the lock to be the instance of the UserModel class 'user'. The threads are supposed to either deposit or withdraw depending on their agent type.
When I execute agent.getT().getState(), it always returns RUNNABLE no matter how many instances of AgentThread I have created. Each AgentThread is given a new agent and a new thread but the same User object. It seems as though the threads are never blocking each other.
I know they are influencing the same user instance because I can output the changes detected by my listener and it reflects all running threads and their interactions with that user instance.
Every time a thread is started it enters an "infinite" loop where the user instance has a deposit or a withdrawal. These actions happen every x seconds.
You threads only lock the User object for enough time to perform a deposit() or withdraw() operation at intervals of, probably, hundreds of milliseconds. Unless deposit() or withdraw() are dependent on high latency external resources, they probably execute in a fraction of a microsecond, which would be enough for, say, thousands of lines of code. As a result, your chances of catching the system in a state where a thread has the User object locked are probably less than 1 in 100,000. In addition, for another thread to be blocked, it too would need to be trying to perform a deposit() or withdraw() operation. Given your likely parameters, the chances of such a collision are less than one in a million, which likely explains why you've never seen it.
When I execute agent.getT().getState(), it always returns RUNNABLE no matter how many instances of AgentThread I have created.
Right. This is because you are calling the agent.getT().getState() from inside of the thread itself. The thread will always see itself as RUNNABLE. When it is blocked or waiting, it isn't looking.
It seems as though the threads are never blocking each other.
No, as I read the code they are certainly blocking each other if they are working on the same User object. However, you are never calling agent.getT().getState() from another thread so it can see the BLOCKED or WAITING states.
One way to look at thread externally is by turning on JMX and using jconsole. If you go to the threads tab, you should be able to see the "Total blocked" and "Total waited" counts increase on your worker threads.
Every time a thread is started it enters an "infinite" loop where the user instance has a deposit or a withdrawal. These actions happen every x seconds.
I assume that's what you are expecting.

Multi-threading program to print numbers from 1 to 50?

im trying to write a program in which two threads are created and the output should be like 1st thread prints 1 and the next thread prints 2 ,1st thread again prints 3 and so on. im a beginner so pls help me clearly. i thought thread share the same memory so they will share the i variable and print accordingly. but in output i get like thread1: 1, thread2 : 1, thread1: 2, thread2 : 2 nd so on. pls help. here is my code
class me extends Thread
{
public int name,i;
public void run()
{
for(i=1;i<=50;i++)
{
System.out.println("Thread" + name + " : " + i);
try
{
sleep(1000);
}
catch(Exception e)
{
System.out.println("some problem");
}
}
}
}
public class he
{
public static void main(String[] args)
{
me a=new me();
me b=new me();
a.name=1;
b.name=2;
a.start();
b.start();
}
}
First off you should read this http://www.oracle.com/technetwork/java/codeconventions-135099.html.
Secondly the class member variables are not shared memory. You need to explicitly pass an object (such as the counter) to both objects, such that it becomes shared. However, this will still not be enough. The shared memory can be cached by the threads so you will have race-conditions. To solve this you will need to use a Lock or use an AtomicInteger
It seems what you want to do is:
Write all numbers from 1 to 50 to System.out
without any number being printed multiple times
with the numbers being printed in order
Have this execution be done by two concurrent threads
First, let's look at what is happening in your code: Each number is printed twice. The reason for this is that i is an instance variable of me, your Thread. So each Thread has its own i, i.e., they do not share the value.
To make the two threads share the same value, we need to pass the same value when constructing me. Now, doing so with the primitive int won't help us much, because by passing an int we are not passing a reference, hence the two threads will still work on independent memory locations.
Let us define a new class, Value which holds the integer for us: (Edit: The same could also be achieved by passing an array int[], which also holds the reference to the memory location of its content)
class Value{
int i = 1;
}
Now, main can instantiate one object of type Value and pass the reference to it to both threads. This way, they can access the same memory location.
class Me extends Thread {
final Value v;
public Me(Value v){
this.v = v;
}
public void run(){
for(; v.i < 50; v.i++){
// ...
}
public static void main(){
Value valueInstance = new Value();
Me a = new Me(valueInstance);
Me b = new Me(valueInstance);
}
}
Now i isn't printed twice each time. However, you'll notice that the behavior is still not as desired. This is because the operations are interleaved: a may read i, let's say, the value is 5. Next, b increments the value of i, and stores the new value. i is now 6. However, a did still read the old value, 5, and will print 5 again, even though b just printed 5.
To solve this, we must lock the instance v, i.e., the object of type Value. Java provides the keyword synchronized, which will hold a lock during the execution of all code inside the synchronized block. However, if you simply put synchronize in your method, you still won't get what you desire. Assuming you write:
public void run(){ synchronized(v) {
for(; v.i < 50; v.i++) {
// ...
}}
Your first thread will acquire the lock, but never release it until the entire loop has been executed (which is when i has the value 50). Hence, you must release the lock somehow when it is safe to do so. Well... the only code in your run method that does not depend on i (and hence does not need to be locking) is sleep, which luckily also is where the thread spends the most time in.
Since everything is in the loop body, a simple synchronized block won't do. We can use Semaphore to acquire a lock. So, we create a Semaphore instance in the main method, and, similar to v, pass it to both threads. We can then acquire and release the lock on the Semaphore to let both threads have the chance to get the resource, while guaranteeing safety.
Here's the code that will do the trick:
public class Me extends Thread {
public int name;
final Value v;
final Semaphore lock;
public Me(Value v, Semaphore lock) {
this.v = v;
this.lock = lock;
}
public void run() {
try {
lock.acquire();
while (v.i <= 50) {
System.out.println("Thread" + name + " : " + v.i);
v.i++;
lock.release();
sleep(100);
lock.acquire();
}
lock.release();
} catch (Exception e) {
System.out.println("some problem");
}
}
public static void main(String[] args) {
Value v = new Value();
Semaphore lock = new Semaphore(1);
Me a = new Me(v, lock);
Me b = new Me(v, lock);
a.name = 1;
b.name = 2;
a.start();
b.start();
}
static class Value {
int i = 1;
}
}
Note: Since we are acquiring the lock at the end of the loop, we must also release it after the loop, or the resource will never be freed. Also, I changed the for-loop to a while loop, because we need to update i before releasing the lock for the first time, or the other thread can again read the same value.
Check the below link for the solution. Using multiple threads we can print the numbers in ascending order
http://cooltekhie.blogspot.in/2017/06/#987628206008590221

How to reproduce race condition in java?

I tried to create a race condition like this.
class Bankaccount {
private int balance=101;
public int getBalance(){
return balance;
}
public void withdraw(int i){
balance=balance-i;
System.out.println("..."+balance);
}
}
public class Job implements Runnable{
Bankaccount b=new Bankaccount();
public void run(){
if(b.getBalance()>100){
System.out.println("the balanced ammount is"+b.getBalance());
/*try{
Thread.sleep(9000);
}
catch(Exception e){
}*/
makeWithdrawl(100);
}
}
public void makeWithdrawl(int ammount){
b.withdraw(ammount);
System.out.println(b.getBalance());
}
public static void main(String[] args) {
Job x=new Job();
Job y=new Job();
Thread t1=new Thread(x);
Thread t2=new Thread(y);
t1.start();
t2.start();
}
}
I am getting output:
the balanced ammount is101
...1
1
the balanced ammount is101
...1
I was expecting it to be in negative as two times withdrawal happened for 100
What is missing here? Thanks in Advance
Race conditions appear when multiple threads change shared data. In your example each thread has its own Bankaccount class. You need to make it shared, like this:
class Job implements Runnable{
Bankaccount b;
Job(Bankaccount b){
this.b = b;
}
public void run(){
if (b != null)
if(b.getBalance()>100){
System.out.println("the balanced ammount is " + b.getBalance());
makeWithdrawal(100);
}
}
public void makeWithdrawal(int ammount){
b.withdraw(ammount);
System.out.println(b.getBalance());
}
public static void main(String[] args) {
// Creating one Bankaccount instance
Bankaccount b = new Bankaccount();
// Passing one instance to different threads
Job x=new Job(b);
Job y=new Job(b);
Thread t1=new Thread(x);
Thread t2=new Thread(y);
// Race conditions may appear
t1.start();
t2.start();
}
}
Unfortunately, this is not enough. Multithreaded programs are non deterministic and you can receive different results after several executions of the program. For example, thread t1 can manage to make withdrawal before thread t2 started to check the balance. Hence, t2 will not do withdrawal due to the lack of money.
To increase the likelihood of negative balance you can insert delay between checking the balance and withdrawing money.
There are several things you need to understand about this.
1) Your particular JVM on your particular system may be impervious to race conditions you are trying to reproduce here.
2) You are not likely to reproduce a race condition with a single run. It's supposed to be non-deterministic, if it gave consistent results it wouldn't be a race condition, but rather an error. To improve your chances make an automated sanity check and run the code 100k times.
3) Using memory barriers so that both threads start at the same time increases the chances a race condition will occur. Using a multi-core system helps too.
4) Your code cannot produce a race condition anyway. Look closely - each job is using it's own account. For a race condition you need shared state.
Your code cant create a race condition, but here is some information for you.
Reproducing a race condition reliably is going to be really hard to do because multi threaded programs are inherently non-deterministic. This means that there is no gaurunteed order to the order in which independent commands in independent threads execute.
This discussion has some good information on the topic:
Can a multi-threaded program ever be deterministic?
What I think you mean in your example, is that you want the balance to be garunteed to have a specific value after a thread executes on it. To do that, You will have to use locks to make sure the only one thread accesses the variable in question at a time.
A lock makes sure that any thread which attempts to read that value while some other thread is manipulating it, must wait until the thread manipulating the variable completes before it can then read and use the variable itself.
You will need locks to do what you are trying to do in your example
Here is the official documentation on using locks to protect
variables, it includes a small example
http://docs.oracle.com/javase/tutorial/essential/concurrency/newlocks.html
This Discussion has a good answer about utilizing locks
in java
Java Thread lock on synchronized blocks
try this code to generate a race condition
// This class exposes a publicly accessible counter
// to help demonstrate data race problem
class Counter {
public static long count = 0;
}
// This class implements Runnable interface
// Its run method increments the counter three times
class UseCounter implements Runnable {
public void increment() {
// increments the counter and prints the value
// of the counter shared between threads
Counter.count++;
System.out.print(Counter.count + " ");
}
public void run() {
increment();
increment();
increment();
}
}
// This class creates three threads
public class DataRace {
public static void main(String args[]) {
UseCounter c = new UseCounter();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
Thread t3 = new Thread(c);
t1.start();
t2.start();
t3.start();
}
}
and try this code to fix it
public void increment() {
// increments the counter and prints the value
// of the counter shared between threads
synchronized(this){
Counter.count++;
System.out.print(Counter.count + " ");
}
}
this code snippet is from the book "Oracle Certified Professional Java SE 7 Programmer Exams 1Z0-804 and 1Z0-805" written by SG Ganesh, Tushar Sharma

Java and Synchronization issues

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.

Categories

Resources