5

Intro:

I want to create a multithreaded android app. My problem is the communication between the threads. I read about communication between threads and I came across stuff like Looper/Handler design, which seemed quite involved and Atomic Variables like AtomicInteger. For now, I used AtomicInteger as a communication but since I am not very experienced in Java, I am not sure if that is bad in my case/ if there is a better solution for my particular purpose. Also I got a little suspicious of my method, when I noticed I need actually something like AtomicFloat, but it's not existing. I felt like I am missusing the concept. I also found that you can make yourself an AtomicFloat, but I am just not sure if I am on the right way or if there is a better technique.

Question: Is it ok/good to use Atomic Variables and implement also AtomicFloat for my particular purpose (described below) or is there a better way of handling the communication?

Purpose/Architecture of the App using AtomicVariables so far:

I have 4 Threads with the following purpose:

1.SensorThread: Reads sensor data and saves the most recent values in AtomicVariables like

AtomicFloat gyro_z,AtomicFloat gyro_y, ...

2.CommunicationThread: Communication with the PC, interprets commands which come form the socket and set the state of the app in terms of a AtomicInteger: AtomicInteger state;

3.UIThread: Displays current sensor values from AtomicFloat gyro_z,AtomicFloat gyro_y,

4.ComputationThread: uses sensor values AtomicFloat gyro_z,AtomicFloat gyro_y, ... and state AtomicInteger state to perform calculation and send commands over USB.

Dimitar Ho
  • 219
  • 1
  • 12
  • It sounds like you could do with a volatile float. – assylias Sep 25 '12 at 10:47
  • Please take a look at this post: http://stackoverflow.com/questions/5505460/java-is-there-no-atomicfloat-or-atomicdouble – Sebastian Breit Sep 25 '12 at 10:49
  • @Perroloco I read that, but the lower two replies were saying that one uses that really rare. To me it seemed very logical that AtomicFloat should exists. that why I questioned my use of them – Dimitar Ho Sep 25 '12 at 10:53
  • @assylias, isn't the use of volatile make problems in case one thread is reading the variable while another one is writing to it? volatile is only needed to receive always the most updated value of a variable right? – Dimitar Ho Sep 25 '12 at 10:57
  • @DimitarM.H. Yes - basically, the only difference between an AtomicInteger and a volatile int, is that AtomicInteger provides atomic operations such as incrementAndGet. So `int j = ++i;` is not atomic if `i` is a volatile int while `int j = i.incrementAndGet();` is atomic if `i` is an `AtomicInteger`. So unless you need that kind of atomic operations, you can simply use a volatile float. Volatile will give you the guarantee that changes made in one thread will be visible in another thread. – assylias Sep 25 '12 at 11:07
  • ok, so for example: i could pass the "reader" thread the volatile float a in the constructor and the "writer" thread also the volatile float a and then there would be no problem if happens that both read/write on it at the same time? or is that only a problem if two threads try to write at the same time? – Dimitar Ho Sep 25 '12 at 11:14
  • Sorry, I tried to understand how I can use volatile for thread communication, but I don't see how to do it.. The point is all my threads are separately written classes. In code, I build them by passing the same atomicInteger variable in their constructor which they save as an object field. With the methods AtomicInteger.set and .get I am working from all threads on the same object. Now volatile seems to be just a specifier of a variable. I don't see how to use it in the same context. should I post a separate question? – Dimitar Ho Sep 25 '12 at 12:44

2 Answers2

1

You basically have a readers writers problem, with two readers and (for the moment) only one writer. If you just want to pass simple types between threads, an AtomicInteger or a similarly implemented AtomicFloat will be just fine.

However, a more accommodating solution, which would enable you to work with more complex data types would be a ReadWriteLock protecting the code where you read or write your object data:

e.g.:

private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); //the reentrant impl

....

public void readMethod() {

    readWriteLock.readLock().lock();

    try {
        //code that simply _reads_ your object
    } finally {
        readWriteLock.readLock().unlock();
    }

}

public void writeMethod() {

     readWriteLock.writeLock().lock();

     try {
        //... code that modifies your shared object / objects
     } finally {
         readWriteLock.writeLock().unlock();
     }
}

This will only enable "one writer-only" or "multiple reader" scenarios for access to your shared objects.

This would enable you for example to work with a complex type that looks like this:

public class SensorRead {

    public java.util.Date dateTimeForSample;

    public float value;

}

While using this data type you should care if the two fields are set and modified safely and atomically. The AtomicXXX type objects are not useful anymore.

Tudor Vintilescu
  • 1,450
  • 2
  • 16
  • 28
0

You have to first ask yourself if you truly need the functionality of a theoretical AtomicFloat. The only benefit you could have over a simple volatile float is the compareAndSet and the addAndGet operations (since I guess increment and decrement don't really make sense in the case of floats).

If you really need those, you could probably implement them by studying the code of AtomicInteger e.g.:

public final int addAndGet(int delta) {
    for (;;) { 
       int current = get();
       int next = current + delta;
       if (compareAndSet(current, next))
           return next;
    }
}

Now the only problem here is that compareAndSet uses platform-specific calls that don't exist for floats, so you'll probably need to emulate it by using the Float.floatToIntBits method to obtain an int, then use the CAS of AtomicInteger, something like:

private volatile float value;

public final boolean compareAndSet(float expect, float next) {
    AtomicInteger local = new AtomicInteger();
    for(;;) {
        local.set(Float.floatToIntBits(value)); 
        if(local.compareAndSet(Float.floatToIntBits(expect), 
                               Float.floatToIntBits(next)) {
            set(Float.intBitsToFloat(local.get()));
            return true;
        }
    } 
}

public final float addAndGet(float delta) {
    for (;;) { 
       float current = get();
       float next = current + delta;
       if (compareAndSet(current, next))
           return next;
    }
}
Tudor
  • 61,523
  • 12
  • 102
  • 142