3

From other questions, I learned that the elements of a volatile array are not volatile. Only the reference itself is volatile.

volatile[] int data;

Thread A: data[4] = 457;
Thread B: System.out.println(data[4]);

Here, Thread B might never see the updated value.

Which options/alternatives do I have to achieve the same thing? I would like to avoid having to synchronize the array, since it is hardly ever altered. However, it is being read a lot by some threads. Synchronizing it will very likely lower the throughput, which is very important in this example.

Is my only option a copy-on-write data-structure here? That is, copying the array into a new array and update the array reference afterwards.

Are there any other options? I read somewhere that encapsulating the array into a class (with only one member, the array) achieves the same thing, but I doubt that is true. I cannot see how that might help.

Please note that my target JVM is 1.4. This means I cannot use the java.util.concurrent package.

-------------- edit edit edit --------------

In Java volatile array? I read that re-assigning the array reference achieves the volatility semantics. This should give the correct results:

volatile[] int data;

Thread A: data[4] = 457;
Thread A: data = data;
Thread B: System.out.println(data[4]);

Is this valid on older JVMs?

Joape Maxe
  • 71
  • 6
  • I updated my question. See below the edit line. – Joape Maxe Apr 01 '13 at 10:23
  • Are you sure that you need to avoid synchronization? you say that synchronizing it "will very likely lower the throughput" - ok, but perhaps you should write the synced code and benchmark it to find out if the performance is OK (i.e. try to avoid premature optimisation?) – Wayne Uroda Apr 01 '13 at 10:28
  • I am pretty sure it will. I am targeting an old JVM, and have improved by performance in the past by replacing synchronized with copy-on-write data-structures and volatile access. I would like to do the same here. – Joape Maxe Apr 01 '13 at 10:33
  • How about this: can each thread hold an entire copy of the array, and you can update each thread's copy when the data changes (not often) by use of a callback or other update function over each thread? (or use a volatile bool to mark when the thread should update its values from the master copy?) – Wayne Uroda Apr 01 '13 at 10:33
  • This is a very useful comment, smart idea. I'll think about this. Thanks a lot. Did you also see my edit? Will this work? – Joape Maxe Apr 01 '13 at 10:37
  • assigning data = data? I have a feeling that this line would be optimised out by the compiler since it has no effect. Unfortunately I can't say I know enough about low-level java to say anything more - my C experience tells me that the compiler (in my experience) does not cache items inside arrays. I can only guess if java has the same kind of behaviour (also I'm sure there is probably no guarantee that C doesn't cache inside arrays if the compiler is sufficiently informed). – Wayne Uroda Apr 01 '13 at 10:43
  • "Support and **security updates** for Java 1.4 **ended in October 2008**." (via [Wikipedia](http://en.wikipedia.org/wiki/Java_version_history#J2SE_1.4_.28February_6.2C_2002.29)). Tell this to whoever forces you to use an ancient Java version. It is very possible that using such an old Java version opens them up to sever legal threats. – Joachim Sauer Apr 01 '13 at 10:43
  • can I ask, what problem are you solving? Why do you need "a lot of threads" - can you reshape the problem into a queue of work that is processed on one thread only (or as many threads as you have CPUs/cores)? – Wayne Uroda Apr 01 '13 at 10:49
  • Joachim: I know, but it is out of my hands. – Joape Maxe Apr 01 '13 at 10:54
  • Wayne: Actually, I am writing some kind of event queue (on which work to be executed can be pushed) which is backed by several threads. These threads share the array. – Joape Maxe Apr 01 '13 at 10:56
  • @JoapeMaxe Regarding your second example (with `data = data`): (i) I am not 100% sure whether it would be legal for a compiler/JVM to ignore the `data = data` as a no-op - if it is you would lose the volatile visibility guarantee. (ii) with Java 5+, volatile guarantees visibility of other variables but I don't think that Java 1.4 does so it would not solve your issue anyway. – assylias Apr 01 '13 at 12:33

3 Answers3

1

An array is marked volatile, that is only the reference is marked as volatile. The elements of array itself do not inherit the memory visibility semantics of the volatile keyword at all.

What I can suggest build a AtomicIntergerArray class in your own. Where you can keep a final int[] data refernece and synchronize it properly.

Also take a look on AtomicIntergerArray implementation code.

Or else you can use Backport api's AtomicIntegerArray.

This project is to provide a concurrency library that works with uncompromised performance on all Java platforms currently in use, allowing development of fully portable concurrent applications. More precisely, the traget scope is Java 1.3 and above, and some limited support if offered for Java 1.2.

Subhrajyoti Majumder
  • 40,646
  • 13
  • 77
  • 103
  • Please read my question. :) I would like to avoid synchronization. – Joape Maxe Apr 01 '13 at 08:32
  • Actually I read it, But I could not find any other way to acheive it. Or you can use backport api's `AtomicIntegerArray`. – Subhrajyoti Majumder Apr 01 '13 at 08:37
  • Thanks. The "problem" is that these backport APIs use synchronized, and I would like to avoid that here. I need to access this array by a lot of threads, and given that the array is hardly ever updated, I should try to eliminate the synchronized locks. – Joape Maxe Apr 01 '13 at 10:22
1

Just use wrapper:

class VolatileInt{
    volatile int value;
}

VolatileInt[] create(int size){
    VolatileInt[] array = new VolatileInt[size];
    for(int k=0;k<size;k++)
        array[k]=new VolatileInt();
    return array; 
}

VolatileInt[] array = create(10);
Lev
  • 921
  • 7
  • 15
1

Using arr=arr manages Java to rewrite the storage address of the array (arrays are also objects in Java). The array fields arr[i] do not gain the volatile property.

In some cases, arr=arr might work for unknown reasons, but it does not bring you to the safe side.

If you want to stay safe, use the Atomic*Array stuff. Yes, the extra atomicity is costly, but I guess if you consider access times and storage footprint it is better than linked structures.

If you want to avoid global locks, you may consider to split the array into subsets. This makes locks affect only a subset and you still keep the volatility for all values.

I share your problem, by best bet are Atomic*Arrays.

Yoh Deadfall
  • 2,711
  • 7
  • 28
  • 32
markus
  • 511
  • 1
  • 4
  • 15