views:

297

answers:

4

Hi,

I have two threads. One invokes the update method of a class that modifies a variable. Another invokes the update method of a class that reads the variable. Only one thread writes and one (or more) threads read that variable. What do I need to do in terms of concurrency, since I am new to multi-threading?

public class A
{
    public int variable; // Does this need to be volatile?
       // Not only int, could also be boolean or float.
    public void update()
    {
        // Called by one thread constantly
        ++variable;
        // Or some other algorithm
        variable = complexAlgorithm();
    }
}

public class B
{
    public A a;
    public void update()
    {
        // Called by another thread constantly
        // I don't care about missing an update
        int v = a.variable;
        // Do algorithm with v...
    }
}

Thanks,

+6  A: 

Not only should variable be volatile, but you also want to protect your update function with some sort of synchronization since ++variable is not an atomic call. It is, after all, just syntactic sugar for

variable = variable + 1;

which is not atomic.

You should also wrap any calls that read variable in a lock of some sort.

Alternatively, use an AtomicInteger. It was made for this sort of thing (for just integer operations).

public class A
{
    // initially had said volatile wouldn't affect this variable because
    // it is not a primitive, but see correction in comments
    public final AtomicInteger variable; // see comments on this issue of why final
    public void update()
    {
        // Called by one thread constantly
        variable.getAndIncrement(); // atomically adds one
    }
    public int retrieveValue()
    {
        return variable.get(); // gets the current int value safely
    }
}

public class B
{
    public A a;
    public void update()
    {
        // Called by another thread constantly
        int v = a.retrieveValue();
        // Do algorithm with v...
    }
}

For the more complex algorithms, as your recent edit assumes, use synchronization or locks.

justkt
By saying "some sort of a lock", you mean "put it in a synchronized block or make the method synchronized" isn't it ?Besides, +1 wih the AtomicInteger
Riduidel
Or use a `java.util.concurrent.Lock` of some sort. I tend to prefer that over `synchronized` for more expressiveness - I like `ReadWriteLock` especially.
justkt
Your comment "volatile won't affect this, it's not a primitive" is misleading. It has nothing to do with whether the field is a primative, but everything to do with the fact that `variable` is no longer being reassigned. Making `variable` final would be advised here.
Mark Peters
@Mark - good correction, thank you.
justkt
I made some adjustments. What if I also need boolean and float. And what if I don't care about missing updates?
Dave
@Dave - AtomicBoolean: http://download-llnw.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/atomic/AtomicBoolean.html. There is no AtomicFloat. Consider instead using the synchronization and lock tutorials linked above to lock your access to those variables. If more than one variable represents your state, lock all variables instead of using atomic classes - those only make access to one state object at a time safe.
justkt
You don't need synchronization on update if it's done in a single thread and reads are atomic.
starblue
+6  A: 

In this case I would use an AtomicInteger, however the generalised answer is that access to variable should be protected by a synchronized block, or by using another part of the java.util.concurrent package.

A couple of examples:

Using synchronized

public class A {
    public final Object variable;
    public void update() {
        synchronized(variable) {
            variable.complexAlgorithm();
        }
    }
}

public class B {
    public A a;
    public void update() {
        sychronized(a.variable) {
            consume(a.variable);
        }
    }
}

Using java.util.concurrent

public class A {
    public final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public final Object variable;
    public void update() {
        lock.getWriteLock().lock();
        try {
            variable.complexAlgorithm();
        } finally {
            lock.getWriteLock().unlock();
        }
    }
}

public class B {
    public A a;
    public void update() {
        a.lock.getReadLock().lock();
        try {
            consume(a.variable);
        } finally {
            a.lock.getReadLock().unlock();
        }
    }
}
Jon Freedman
+5  A: 

Use AtomicInteger or synchronize the access to be safe.

PartlyCloudy
can you please explain what you mean by synchronize?Like where it should go, its a tad confusing for me.
Dave
@Dave - http://download.oracle.com/javase/tutorial/essential/concurrency/sync.html should help you out with basic Java synchronization.
justkt
+3  A: 

If there is one and only one thread that writes to variable you can get away with making it volatile. Otherwise see the answer with AtomicInteger.

Only volatile will work in case of only one writing thread because there is only one writing thread so it always has the right value of variable.

hidralisk
That was my point. I know that only one thread modifies it but there could be many threads reading it.
Dave
@Dave - well, this is why I posted this answer. If your multi-threading is simple, only one thread writes and you have only one variable that it writes to for the other threads to read, you do not need a complex solution, volatile int variable will do. In a general case you would probably want Locks, synchonized or AtomicInteger. But your question was pretty specific on the number of writer threads and number of variables involved. Don't be intimidated by the votes on other answers. If my solution suites your needs, accept it.
hidralisk
@hidralisk - Thanks very much I just needed a second opinion. I also never knew about Atomic variables and other goodies in the concurrency package that I'm happy people here were kind enough to explain. It may prove valuable to me in the future.
Dave