10

Question I've had for years: In this pseudocode,

ExecutorService svc = Executors.newFixedThreadPool(3);
svc.submit(new Runnable() { /* code A */ });
svc.shutdown();
if(svc.awaitTermination(...)) {
    // code B

.awaitTermination() is not documented as establishing happens-before between code A & B. Is there a reason it isn't ?

The ExecutorService and concurrent package javadocs define happens-before between the tasks and work done before they were submitted, but not between executor tasks and code after a successful .awaitTermination() call.

Note, I'm not asking for design critiques on how to restructure my code to leverage documented happens-before relationships. My question here is, is there a reason the docs don't mention happens-before in this situation?

(Note that this is not a duplicate of 22665198 despite the very apt title.)

Community
  • 1
  • 1
tariksbl
  • 1,069
  • 6
  • 20
  • Logic dictates that there should be a happens-before ordering, but you're right OP, I can't find it documented anywhere. – John Vint Jun 02 '15 at 19:57
  • 1
    The only "official" guarantee is that if you retrieve the future with `Future> f = svc.submit(...)` AND you call `f.get()`, then you have your hb relationship. – assylias Jun 02 '15 at 21:21
  • @assylias so, why is that? Do I really have to `.get()` every task? I know I've written lots of code that assumes a successful `.awaitTermination()` establishes *happens-before*. – tariksbl Jun 02 '15 at 22:03
  • I would simply say - Yes, if and only if `awaitTermination()` returned `true`. – Antoniossss Jun 03 '15 at 11:39
  • 1
    @tariksbl Just because it works now and often doesn't mean it will have to work all the time. In short, what if the synchronization used for starting a task and setting the task in the future is different than the synchronization used to shut down an ExecutorService? In that case you may not have the relationship you're hoping for and can 'fail' sometime in the future. – John Vint Jun 03 '15 at 16:46
  • There are tests for JSR166 (java.util.concurrent) which runs under the acceptance that *there is a very high probability everything works*. – John Vint Jun 03 '15 at 16:47

2 Answers2

2

ExecutionService, are you sure? Did you mean ExecutorService? Also, there is no ExecutorService.awaitTermination() method without parameters. The ExecutorService.awaitTermination(long, TimeUnit) method receives the amount of time to wait until timeout. Obviously, if it returns because of the timeout, it cannot guarantee the happens-before relationship, thus it cannot advertise this guarantee in its contract, because it is not there for all cases.

Forketyfork
  • 7,416
  • 1
  • 26
  • 33
  • 4
    Why can't the Javadocs say *If this call returns normally it establishes a happens-before ordering*? – John Vint Jun 02 '15 at 20:06
  • @JohnVint Because this information would be useless, as it would be known only at runtime. You have to rely on this ordering to write correct code in the first place. – Forketyfork Jun 02 '15 at 20:11
  • 2
    @SergeyPetunin Would you say that Lock's `tryLock` doesn't establish happens-before ordering? https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Lock.html#tryLock%28long,%20java.util.concurrent.TimeUnit%29 – John Vint Jun 02 '15 at 20:13
  • If the locking mechanism is the same for `awaitTermination` then the same reasoning would apply that `awaitTermination` would establish a happens-before ordering. If it's different synchronization than obviously the timing has nothing to do with it and there is no relationship. – John Vint Jun 02 '15 at 20:14
  • 1
    `Thread.join()` can time out, in which obviously there's no happens-before. Seems logical to assume an implicit "..if successful" – tariksbl Jun 02 '15 at 20:23
  • @tariksbl @JohnVint you're right, my answer is most likely incorrect. Still your code example should be corrected to check for return result: `if (svc.awaitTermination(...)) { /* code B */}` – Forketyfork Jun 02 '15 at 20:44
-1

Actually you are wrong as it IS documented

Blocks until all tasks have completed execution after >a shutdown request, or the timeout occurs, or the >current thread is interrupted, whichever happens first.

So it IS guaranteed that either task will be compleated or timeout will occure. The thig is that we only needs to distinguish these situations by checking the return value of awaitTermination method. It will be true if tasks are completed. False if timeout or interruption.

Antoniossss
  • 31,590
  • 6
  • 57
  • 99
  • Memory consistency is different- see https://docs.oracle.com/javase/tutorial/essential/concurrency/memconsist.html – tariksbl Jun 03 '15 at 00:38
  • Not related at all in this situation. There are no race conditions between worker threads and thread from outside of the pool waiting for its termination. – Antoniossss Jun 03 '15 at 06:59
  • 1
    @Antoniossss worker threads and outside thread share same memory, how can you be sure there are no race conditions? Suppose one of the workers writes value to a static field, and the outside thread tries to read it after `awaitTermination` returns `true`. What are the guarantees that the outside thread will observe that write, if happens-before is not enforced? – Forketyfork Jun 03 '15 at 11:27
  • Because worker threads are to be in idle state before awaitTermination returns with `true` so all writes are to be done by that point. Am i missing something here? Cuz this is quite obvious form me. – Antoniossss Jun 03 '15 at 11:36
  • 1
    @Antoniossss what do you mean by "writes are done"? What are the guarantees that those writes are ordered with memory barriers, that they are not cached, that the outside thread won't observe its own cached read? If there is no synchronization edge between the worker transitioning to an idle state and the outside thread reading from memory after the call to `awaitTermination`, then there is no data race guarantee. – Forketyfork Jun 03 '15 at 12:17
  • @Antoniossss oldie but goodie on memory consistency: http://www.javaworld.com/article/2074990/java-concurrency/warning--threading-in-a-multiprocessor-world.html – tariksbl Jun 03 '15 at 13:55