Is calling start() on a object of this class safe? An example from Java Concurrency in practice

情到浓时终转凉″ 提交于 2019-12-02 16:23:16

问题


First off, I will give links to the source code that I will be talking about since copy/paste would make this question page too long.

In Listing 5.15 http://jcip.net/listings/CellularAutomata.java of JCIP, I imagine that in some main method, one will create a CellularAutomata object and then call start() on that object.

However, is it okay to do so? When the object's start method is called, it will create N(number of processors) threads with instances of Worker. It seems though that the N threads that are created with the worker object might be seeing a incomplete reference or object of that Worker.

The reasoning behind it is that, the this reference escapes during the construction of the CellularAutomata object when calling new Runnable() and new Worker(mainBoard.getSubBoard(count, i))

And since Worker[] workers; and CyclicBarrier barrier; are fields of the CellularAutomata object, the threads created in the start() method of that object might not be able to see those objects in a proper state.

I am thinking this is similar to the Holder's example http://jcip.net/listings/StuffIntoPublic.java http://jcip.net/listings/Holder.java where the Holder's field might not be visible by other threads. I understand that the Holder example was problematic because the field was not final, and therefore might not be visible, and in the CellularAutomata they are final. I read that class with only final fields are guaranteed visibility for their fields when published. However, I also read that although final fields might be the only fields of a class, if the class is not properly constructed, then that guarantee is gone. And in this example, since the this reference escapes, I assume it is not properly constructed. Here is an example of implicitly letting the this reference escape which is similar to what's going on in CellularAutomata. http://jcip.net/listings/ThisEscape.java

Please let me know if my thoughts need correction, I would really appreciate it. This concurrency journey has been filling me with so many doubts and questions and if you have any other references to where I can learn concurrency and the foundations for concurrency in Java, please let me know.

Thank you


回答1:


You can read the relevant section the Java Language Specification: 17.5. final Field Semantics

The first relevant section (emphasis added by me):

An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields.

The this references is not seen by any other thread before the constructor completes, so it's fine. There is nothing magic about the this reference "escaping" from the constructor; the relevant thing is that no other thread should see it (before the constructor completes).

The next paragraph in the JLS expands on this (emphasis and italics added by me):

The usage model for final fields is a simple one: Set the final fields for an object in that object's constructor; and do not write a reference to the object being constructed in a place where another thread can see it before the object's constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields.




回答2:


The danger in allowing this to escape is that it might be seen before it's fully constructed. In this case, that's not an issue because the runnable doesn't execute until start() is invoked, which must be after the constructor completes.

Furthermore, besides the final field guarantees, there are at least two additional happens-before barriers between the assignment of mainBoard and the execution of the runnable. One is the call to Thread.start() by what will be the last thread entering the barrier, which happens-before any action in the started thread. Then there is the actual call to CylicBarrier.await(), which happen[s]-before actions that are part of the barrier action.

So I would say the code is pretty safe.



来源:https://stackoverflow.com/questions/47988383/is-calling-start-on-a-object-of-this-class-safe-an-example-from-java-concurre

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!