multi-threading, performance and precision consideration

240 Views Asked by At

consider the following class:

public class Money {
    private double amount;

    public Money(double amount) {
        super();
        this.amount = amount;
    }

    public double getAmount() {
        return amount;
    }

    public void setAmount(double amount) {
        this.amount = amount;
    }

    public Money multiplyBy( int factor) {
        this.amount *= factor;
        return this;
    }
}

what are the precautions that i can take to make sure that this class doesn't have any problem with multi-threading. have a good performance. while making sure that the money precision is not going to be problem

4

There are 4 best solutions below

0
On BEST ANSWER

Ahmad, your question is ambiguous enaugh.

About multithreading: It is not clear what you mean by problems with multi-threading. For instance, that class has not any problem with multi-threading in the sense that it is well-synchronized, but you still can set a state of a Money object into the mess, utilizing it by several threads:

public class Money {
    private volatile double amount;

    public Money(double amount) {
        super();
        this.amount = amount;
    }

    public double getAmount() {
        return amount;
    }

    public synchronized void setAmount(double amount) {
        this.amount = amount;
    }

    public synchronized Money multiplyBy( int factor) {
        this.amount *= factor;
        return this;
    }
}

About money precision: As Andreas answered, see: Why not use Double or Float to represent currency?. Also that one may be interesting: What is the best data type to use for money in Java app?

0
On

Maintaining precision

There are a few ways of maintaining precision. The first is to completely avoid fixed-precision floating-point binary number types like floats and doubles if your currency uses decimal digits past the point. Here are a few good alternatives:

BigDecimal

java.math.BigDecimal allows you to store precise finitely-long decimal values with ease, but it can be a bit slow.

Use BigDecimals if you need the programming to be easy and the results to be precise, but you're OK with slowness.

long

long can be used to store the amount in cents rather than dollars if you're using US currency.

For other currencies, you can take the reciprocal of the rational GCD of the currency denominations and multiply everything by that when you store it.

Confused? Here's an example of Wolfram|Alpha doing all the hard work of figuring out from the available US currency denominations ($1/100 through $100) that it should multiply US currency by 100. Make sure to use fractions rather than decimals with this.

Use longs if you need a lot of speed and are OK with the drawback that monetary amounts greater than US$92,233,720,368,547,758.07 give completely incorrect results.

Besides being fast by themselves, longs also use a lot less memory and never require garbage collection of themselves, so that's another small speedup for them.

BigInteger

longs can be replaced with java.math.BigIntegers to avoid any overflow problems.

Use this if you want something in between the speed and slowness of the other two with no reasonable chance of ever overflowing.

0
On

There are a couple key points to make a POJO (Plain Old Java Object) thread safe:

  1. Make the class immutable. If you add any instance variables, make them either final or volatile.

  2. Make your getters and setters synchronized, i.e.

    public synchronized void setAmount(double amount) {}
    
0
On

Ideally if you make a class as immutable, you don’t have to bother about multithreading. But here, you should make the multiplyBy method as mutually executable so that it should not have inconsistent behaviour. Also, you don’t need to provide setter as the only constructor is taking amount as an argument.