0

I have two threads, each has its own counter: thread A has counterA, thread B has counterB. Each thread has to use both counters: thread A has to use counterA and counterB, also thread B has to use both. I am using AtomicInteger and to share the counters between the two threads I am passing them as arguments to the threads and each thread stores the two counters in private fields.

// ...
AtomicInteger counterA = new AtomicInteger(0);
AtomicInteger counterB = new AtomicInteger(0);

Thread tA = new Thread(new RunnableA(counterA, counterB)); 
Thread tB = new Thread(new RunnableB(counterA, counterB)); 

// ... in the constructor of RunnableA ...
RunnableA(AtomicInteger counterA, AtomicInteger counterB) {
    this.counterA = counterA;
    this.counterB = counterB;
} 

//...
// The same for RunnableB

Is this a safe publishing of the two counters? Safe-publishing is necessary because a reference to an object is not safe enough to share the object between threads. How can I achieve safe-publishing in this case?

Thanks in advance.

Community
  • 1
  • 1
Gibezynu Nu
  • 354
  • 6
  • 15

1 Answers1

1

The term "safe publication" is not applicable to this. Safe publication is about the publication of state that is created in the constructor. In your example, the AtomicInteger objects were created before the constructor was called.

If some other type was used, this may or may not be safe depending on whether and how the counterA and counterB variables are published. However, with with counters implemented as AtomicInteger objects, you don't need to worry about publication. They are atomic / thread-safe, irrespective how they are published. The only possible concern might be the publication of the state of the instance variables. We cannot tell whether that occurs without looking at the rest of the class. For example:

  • are the variables final or volatile?
  • if they are non-volatile and non-final, is access to them properly synchronized?
  • are they thread-confined after run() is called?

Note that the runnables will be instantiated in the current thread, not in the threads that are created when (and if) tA.start() and tB.start() are called. When start() is called, there is a happens-before between the current thread's start() call and the new thread's run() call. This means that safe publication of the variables to the child thread itself is guaranteed. It is only publication of the variables to other threads that is of concern.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • "I can't immediately see how that might be" - if the counters are being accessed outside of newly created threads as instance variables of the Runnables. The values initialized in the constructor are not guaranteed to be visible before being accessed unless for example declaring at least one of the instance variables final, see https://shipilev.net/blog/2014/safe-public-construction/ – Tomasz Stanczak Nov 11 '16 at 10:45
  • Well yea ... but how could those variables be accessed by *anything* before the constructor returns? Look at the code for the constructor. (I do know what safe publication means, and `final` is only one way to achieve it.) – Stephen C Nov 11 '16 at 13:21
  • "When start() is called, there is a happens-before between the current thread's start() call and the new thread's run() call. This means that safe publication of the variables to the child thread itself is guaranteed." This is a point I find useful. For example, one does not need to declare the "argument variables" (this.counterA, this.counterB) as final in the Runnable, even-though the Runnable is constructed in the main thread, and later those argument variables are accessed in the thread that is created. – Gibezynu Nu Nov 11 '16 at 17:42
  • The variables this.counterA, this.counterB of RunnableA are used only by thread A, but the objects counterA and counterB are used by both threads (with .get(), .incrementAndGet() methods). – Gibezynu Nu Nov 11 '16 at 17:55
  • @Gibezynu Nu: if the variables are being accessed only from within the Runnables the code will be okay, the memory barriers and happen-befores are sufficient there. I commented only to answer Stephen C's doubt that unsafe initialization (not publication!) might in fact happen. He seems to have partly taken it into account since the answer has changed now and the doubt has been removed. Nevertheless based on your comment I believe that your code is okay and you in fact do not need the instance variables final (even if I do not see any reason not to). – Tomasz Stanczak Nov 14 '16 at 08:50
  • @Stephen C if that was not possible, why write a whole chapter in JLS about exact this issue? Take a look here http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5, also in the paragraph "Safe Initialization" in the article I posted above. – Tomasz Stanczak Nov 14 '16 at 08:57
  • @Stephen C the problem is that after the constructor returns not all of the instance variables set inside the constructor are guaranteed to be seen as properly initialized in other threads. I admit it looks pretty impossible and you may never see it in your life, yet under the race conditions and depending on compilier optimizations it theoretically might happen. And `final` comes here to rescue. – Tomasz Stanczak Nov 14 '16 at 09:51
  • @TomaszStanczak - I know that: *"This means that safe publication of the variables to the child thread itself is guaranteed. It is only publication of the variables to other threads that is of concern."*. Besides, I am talking about what is possible *in the context of this example*. Not in general. In this example, the only publication that is *shown to us* is the publication of the variables from the main thread to the child thread. And **that** publication is safe. – Stephen C Nov 14 '16 at 10:43
  • And besides 2, `final` is not the *only* way to get safe publication, and it is not the appropriate way if (hypothetically) the variable needs to be mutable. (It doesn't in this case ...) – Stephen C Nov 14 '16 at 10:46
  • You certainly mean "variable reference needs to be mutable", isn't it? Because making a mutable type's reference`final` doesn't stop you from mutating the content of the variable. But we are starting hairsplitting here, I think it would be better to stop at this point, since all is already said. – Tomasz Stanczak Nov 14 '16 at 10:57
  • Of course thats what I mean. If I meant making the type mutable, I would have said that. (But saying "making the variable *reference* mutable is redundant. The variable is the thing that holds the reference. It is the "thing that holds the reference" that is mutable not the reference itself. A reference is a pure value, just like an integer value. An application program can't change it. And strictly speaking, a "variable reference" would be a reference *to* a variable. That doesn't exist in Java) – Stephen C Nov 14 '16 at 11:18