Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java class to allow multiple threads to read or one to modify at the same time

Let's say you have the following class:

class A {
    private Foo foo = new Foo();
    Foo getFoo() {
        return foo; //foo.clone()?
    }
    void modifyFoo() {
        //modify this.foo
        //...
    }
}

I want to allow:

  • either multiple threads to call getFoo()
  • or one thread to call modifyFoo(),
  • once a thread wants to modify foo, no other new getFoo() calls arriving after that may be executed, until modification is done.

Are there classes already for this problem in Java or do I have to implement it? If I have to implement it, then how do I implement it ensure thread safety?

like image 488
SolidSun Avatar asked Nov 22 '11 16:11

SolidSun


3 Answers

It sounds like what you're looking for is a Read-Write lock, fortunately, java provides one, ReentrantReadWriteLock. You can use it as follows:

class A {
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private Foo foo = new Foo();
    Foo getFoo() {
        lock.readLock().lock();
        try {
            Foo tmp = foo; //foo.clone()?
        } finally {
            lock.readLock().unlock();
        }
        return tmp;
    }
    void modifyFoo() {
        lock.writeLock().lock();
        try {
            //modify this.foo
            //...
        } finally {
            lock.writeLock().unlock();
        }
    }
}

This will allow any number of threads to call getFoo() simultaneously, but only one to call modifyFoo(). When modify foo is called, the thread will block until all read locks are released, then begin executing and prevent any new read locks from being acquired until it has finished. There are still concurrency issues to consider since the returned Foo can be modified by the code that calls getFoo, but this should provide the basic tool you need.

like image 60
nonVirtualThunk Avatar answered Oct 05 '22 02:10

nonVirtualThunk


You should use a ReentrantReadWriteLock. Multiple threads can read, one thread can write which blocks all reads.

like image 30
Chris Dennett Avatar answered Oct 05 '22 03:10

Chris Dennett


class A {
    private volatile Foo foo = new Foo();
    Foo getFoo() {
        return foo; //foo.clone()?
    }
    void synchronized modifyFoo() {
        //modify this.foo
        //...
    }
}

The synchronized keyword ensures that modifyFoo() is atomic, that is, won't allow multiple threads to invoke it at once. The volatile keyword ensures that reads to foo do not return a cached version (which could have been outdated if another thread modified it) and instead returns the current, correct value.

like image 24
Travis Webb Avatar answered Oct 05 '22 02:10

Travis Webb