Considering the code below.
public class Account {
private static List<Double> log = new ArrayList<Double>();
private double balance;
public Account(){balance = 0.0;}
public synchronized void deposit(double val){
balance = balance + val;
log.add(val);
}
public synchronized void withdraw(double val){
balance = balance - val;
log.add(val);
}
}
Is the synchronization correct?
I would say yes, because the method that access the variable log are atomic (thanks to the word Synchronized).
I tested it in this way:
Account a = new Account();
Thread t = new Thread(()->a.deposit(30));
Thread j = new Thread(()->a.withdraw(20));
t.start();
j.start();
sleep(300);
System.out.println(Account.getLog());
It seems to me that blocking is fine, as long as one thread is using the log variable, the other is not using it.
However, the text shows this solution (not explaining why)(-> stands for substitution):
log.add(val)->
synchronized(log)
{
log.add(val)
}
log.add(-val)->
synchronized(log)
{
log.add(-val)
}
class Account {
private static List<Double> log = new ArrayList<Double>();
private double balance;
public Account() {
balance = 0.0;
}
public synchronized void deposit(double val) {
balance = balance + val;
synchronized (log) {
log.add(val)
}
}
public synchronized void withdraw(double val) {
balance = balance - val;
synchronized (log) {
log.add(-val);
}
}
}
Why should I lock the variable log? Is it not enough to synchronize the method?
The solution code looks thread-safe to me:
The balance variable for each account is updated while holding the account's mutex.
The log is updated while holding the list's mutex.
One small quibble is that log should be final. If anything was able to (for example accidentally) assign a new value to log, different threads are not guaranteed to be seeing / updating the same list object.
However, your version of the code is NOT thread-safe. It is not locking log while updating it. That means that two threads updating different Account objects could simultaneously attempt to update the log list. That could corrupt it.
There are various other things wrong with (both) solutions. The most critical one is that you are using double to represent currency values. That is a violation of normal accounting practice. (And some bank customers will get antsy if you "steal" some of their pennies ... due to floating point rounding errors.)
Related
to begin with, this is my first question in here.
I want to use double mebleg inside transfer method, and I has equaled mebleg to balance in constructor, but unfortunately, the amount of parameter of balance doesn't go with mebleg into transfer method. how can I solve this problem?
I am new at programming. that's why if my question was answered, could you suggest that links of answers?
class Acount {
static double mebleg;
public static void main(String[] args) {
Acount a = new Acount(100);
Acount b = new Acount(0.0);
Acount c = new Acount(0.0);
Acount.transfer(a, b, 50);
Acount.transfer(b, c, 25);
}
public Acount(double balance) {
mebleg = balance;
}
public static void transfer(Acount from, Acount to, double howMuch) {
System.out.println(Acount.mebleg - howMuch);
}
}
You should not make the field static if you want to use it for instances. If you change that, your transfer() method should use from.mebleg (or a associated getter).
double mebleg;
public Account(double initialBalance) { mebleg = initialBalance; }
public static void transfer(Acount from, Acount to, double howMuch)
{
from.mebleg -= howMuch;
to.mebleg += howMuch;
}
(Not discussing various existing issues like transactions, concurrency, error handling and usage of double for monetary units here).
I'm pretty new to Java and need some help with a program I am writing. Basically I have 2 classes that are trying to change the balance of a bank account. One class is adding deposits while the other is withdrawing. I though the easiest way to share a balance between the classes was to make a third class that looks like this:
public class Balance {
static int balance;
public int getBalance(){
return balance;
}
public void returnBalance(int bal){
this.balance = bal;
}
}
I am correctly calling the getBalance method because that is pulling in the correct balance. However, when I use my object Balance balanceCall = new Balance(); to give the changed balance (after depositing), it is not updating the balance within the class. I think I am again calling the method correctly, but it does not appear to actually change the value of the balance variable in my balance class. Is the code in my balance class used incorrectly for the returnBalance method?
Thanks for your help!
UPDATE: I changed the integer to static int balance. It is now updating the value between classes, however it seems to be creating a new value every time i do a deposit.
This is what it looks like:
Thread 1 deposits $76 Balance is $76
Thread 8 withdraws $45 Balance is $31
Thread 7 withdraws $12 Balance is $64
Thread 6 withdraws $41 Balance is $35
Thread 3 deposits $89 Balance is $165
Thread 5 withdraws $10 Balance is $66
Thread 4 withdraws $17 Balance is $59
Thread 2 deposits $157 Balance is $157
Here is how I use the Balance instance:
balanceNum = balanceCall.getBalance();
balanceNum = balanceNum + 25;
balanceCall.returnBalance(balanceNum);
Hopefully this helps to clear things up.
If you want all your objects to share the same balance field you have to add the static modifier. Otherwise a new member will be created for every objects.
If you need just a copy with same balance,
public class Balance {
private int balance;
public int getBalance()
{
return balance;
}
public void setBalance(int b)
{
balance=b;
}
public Balance newBalance()
{
Balance b=new Balance();
b.setBalance(getBalance());
return b;
}
}
usage:
balanceCall=previousBalance.newBalance();
or you can clone too.
Assuming the methods are called correctly, you can share your balance variable by using the static keyword (ex. "static int balance;").
In doing so, you make the variable belongs to all classes within the project and is shared across them. To use this variable, just refer to its name, in this case use "balance = [insert formula];" (no longer need to use "this.balance").
You are creating a new instance of the balance class when you do new balance(). So essentially one class is still referring to the old instance, while the new class is referring to the new one.
The way you should go about this depends a bit on the rest of the program, but if you want to refer to the same instance, you should put an extra method in the balance class, called updateBalance() which changes the balance, or maybe decrements / increments it depending on whether it is a withdrawal or deposit.
However, your design seems to be a bit weird. It seems that both classes performing withdrawals or deposits should actually be referring to the same bank account. The balance class seems a bit redundant.
The static behaviour approach as suggested by others definitely helps achieve a solution, but, keeping in mind your opening line that you're still a beginner in Java, I'd suggest you change your Class design altogether, to make it more in line with an Object Oriented design.
Create a class called Account, with Balance as its attribute. It makes sense to have an Account object (like in the real-world) that HAS a Balance attribute. The withdraw or deposit actions corresponding to an Account can be put within the same Account class, in line with the encapsulation paradigm of OOP/Java. This would help in making it more intuitive to understand the flow of variables within your program.
public class Account{
public int balance = 0;
public void setBalance(int balance){
this.balance = balance;
}
public int getBalance(){
return this.balance;
}
public deposit(int amount){
this.balance += amount;
}
public withdraw(int amount){
//Additional validations can be added to ensure non-negative balance, if needed
this.balance -= amount;
}
}
public AccountDemo{
public static void main(String[] args){
Account account1 = new Account();
account1.deposit(100);
Account account2 = new Account();
account2.deposit(50);
account2.withdraw(10);
//account1 has a balance of 100 & account2 has a balance of 40 at this point
AccountDemo.transferMoney(account1, account2, 20);
//account2 now has a balance of 80 (deducted by 20)
// & account2 has a balance of 60(increased by 20) after the transfer.
}
public static boolean transferMoney(Account source, Account destination, int amount){
if(source.getBalance() >= amount){
source.withdraw(amount);
destination.deposit(amount);
System.out.println("Transfer successful");
return true;
} else{
System.out.println("Sorry. Transfer failed due to
insufficient funds.");
return false;
}
}
}
This seems to be a problem with thread synchronization, namely lost update. This means, if you read and write the same value from multiple threads, some calculations will not be represented in the final result. You can solve this problem using the class AtomicInteger:
public class Balance {
private AtomicInteger value = new AtomicInteger();
public int get() {
return value.get();
}
public void set(int value) {
this.value.set(value);
}
public int addAndGet(int value) {
return this.value.addAndGet(value);
}
}
Right usage:
int value = balance.addAndGet(25);
Wrong usage:
int value = balance.get();
value = value + 25;
balance.set(25);
You have to use the addAndGet method to prevent the problem of lost update.
Also, you should definitely not declare the value attribute as static, because then all of your Balance instances will hold the same value which is probably not what you want.
See also:
Why are static variables considered evil?
Java - using AtomicInteger vs Static int
I've been given the task to find the way to share a method's, involved in several threads, local variable, so it's value would be visible for every thread running this method.
Now my code look's like this:
public class SumBarrier2 implements Barrier {
int thread_num; // number of threads to handle
int thread_accessed; // number of threads come up the barrier
volatile int last_sum; // sum to be returned after new lifecyrcle
volatile int sum; // working variable to sum up the values
public SumBarrier2(int thread_num){
this.thread_num = thread_num;
thread_accessed = 0;
last_sum = 0;
sum = 0;
}
public synchronized void addValue(int value){
sum += value;
}
public synchronized void nullValues(){
thread_accessed = 0;
sum = 0;
}
#Override
public synchronized int waitBarrier(int value){
int shared_local_sum;
thread_accessed++;
addValue(value);
if(thread_accessed < thread_num){
// If this is not the last thread
try{
this.wait();
} catch(InterruptedException e){
System.out.println("Exception caught");
}
} else if(thread_num == thread_accessed){
last_sum = sum;
nullValues();
this.notifyAll();
} else if (thread_accessed > thread_num ) {
System.out.println("Something got wrong!");
}
return last_sum;
}
}
So the task is to replace the class member
volatile int last_sum
with method's waitBarrier local variable, so it's value would be visible to all threads.
Any suggestions?
Is it even possible?
Thanks in advance.
In case the variable last_sum is updated by only one thread, then declaring it volatile will work. If not then you should look at AtomicInteger
An int value that may be updated atomically. See the
java.util.concurrent.atomic package specification for description of
the properties of atomic variables. An AtomicInteger is used in
applications such as atomically incremented counters, and cannot be
used as a replacement for an Integer. However, this class does extend
Number to allow uniform access by tools and utilities that deal with
numerically-based classes.
You can have the practical uses of AtomicInteger here: Practical uses for AtomicInteger
having a look at the netbeans affable bean tutorial. Why do we need the use of synchronized methods here?
public synchronized int getNumberOfItems() {
numberOfItems = 0;
for (ShoppingCartItem scItem : items) {
numberOfItems += scItem.getQuantity();
}
return numberOfItems;
}
public synchronized double getSubtotal() {
double amount = 0;
for (ShoppingCartItem scItem : items) {
Product product = (Product) scItem.getProduct();
amount += (scItem.getQuantity() * product.getPrice().doubleValue());
}
return amount;
}
Looks like every method related to the ShoppingCartItems management is synchronized. Certainly to prevent a concurrent access in the items List (List<ShoppingCartItem> items;).
Without the synchronized, you could have 1+ Thread accessing a 'read' method such as getSubtotal () while the items List is being updated through public synchronized void addItem(Product product) by another Thread.
The source can be found here
maybe because you may shop using two different windows and the cart must be updated properly, so all related methods are marked as synchronized
I'm having some trouble with my java program and I'm not sure if this is the problem but would calling a mutator method on an object inside an araylist work as intended?
For example
public class Account
{
private int balance = 0;
public Account(){}
public void setAmount(int amt)
{
balance = amt;
}
}
public class Bank
{
ArrayList<Account> accounts = new ArrayList<Account>();
public staic void main(String[] args)
{
accounts.add(new Account());
accounts.add(new Account());
accounts.add(new Account());
accounts.get(0).setAmount(50);
}
}
Would this work as intended or is there something that would cause this not to?
Is the problem but would calling a mutator method on an object inside an ArrayList work as intended?
Yes, if your intention is to update the first account in the list. Keep in mind that the array list doesn't store objects, but references to objects. Mutating one of the objects won't change the reference stored in the list.
The first account will be updated, and when referencing accounts.get(0) again it will show the updated balance.
Here's an ideone.com demo demonstrating it. (I've just fixed a few minor typos such as adding static in front of the accounts declaration.)
for (int i = 0; i < accounts.size(); i++)
System.out.println("Balance of account " + i + ": " +
accounts.get(i).balance);
yields
Balance of account 0: 50
Balance of account 1: 0
Balance of account 2: 0
which hopefully is what you would expect.
Yes, that should work as intended. It is no different than:
Account firstAccount = accounts.get(0);
firstAccount.setAmount(50);
Remember, ArrayList's get() method returns the actual object stored in the ArrayList, not a copy of it.