10

Golang has something called a WaitGroup which is sort of like in Java a CompletionService or a CountDownLatch or a Semaphore or some combination of the latter.

I'm not entirely sure how you would implement a WaitGroup in Java. I would imagine a custom CompletionService with some sort of Poison message would be the route to go (since queues can't say when they are done) but perhaps there is a better concurrent data structure/lock?

EDIT I posted a possible solution below using Semaphore that I think is more analogous than using thread.join.

Adam Gent
  • 47,843
  • 23
  • 153
  • 203
  • 3
    possible duplicate of [How to wait for a set of threads to complete?](http://stackoverflow.com/questions/1252190/how-to-wait-for-a-set-of-threads-to-complete) – durron597 Apr 15 '15 at 16:26
  • 2
    I don't know Java but, for the case where you `wg.Add(n)` before starting all *n* tasks, [CountDownLatch](https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html) looks like a fit, using `countDown()` for `wg.Done()` and `await()` for `wg.Wait()`. – twotwotwo Apr 15 '15 at 18:56
  • 2
    The accepted answer on the linked question could work too, since threads are objects in Java. But they're slightly different: with CountDownLatch a thread can do other work after it finishes the task (so you could use it handing tasks to a pool of long-lived threads), with `thread.join()` it can't. Since the tasks differ a little I'm not voting to close as dupe. – twotwotwo Apr 15 '15 at 18:59
  • I'm using CountdownLatch for most cases I'd use a WaitGroup in Go. – Not_a_Golfer Apr 15 '15 at 19:44

5 Answers5

7

WaitGroup has Add(delta) method that can be called after a WaitGroup has been created. CountDownLatch doesn't support this, number of tasks needs to be specified in advance. JDK7 Phaser can be used instead in this case:

phaser.register = wg.Add(1)
phaser.arrive = wg.Done
phaser.await = wg.Wait
kostya
  • 9,221
  • 1
  • 29
  • 36
  • One important note is that the main thread must register or set the number of parties to `1` initially (WaitGroup has this as 0) . If this isn't done, there can be problems with threads arriving at different phases making the final await never complete. – River Oct 27 '22 at 01:06
5
public class WaitGroup {

    private int jobs = 0;

    public synchronized void add(int i) {
        jobs += i;
    }

    public synchronized void done() {
        if (--jobs == 0) {
            notifyAll();
        }
    }

    public synchronized void await() throws InterruptedException {
        while (jobs > 0) {
            wait();
        }
    }

}
user82928
  • 877
  • 7
  • 16
1

Thanks to @kostya's answer. I write a WaitGroup class with Phaser

public class WaitGroup {

    Phaser phaser = new Phaser(1);

    public void add() {
        phaser.register();
    }

    public void done() {
        phaser.arrive();
    }

    public void await() {
        phaser.arriveAndAwaitAdvance();
    }
}

Yao Yuan
  • 350
  • 3
  • 11
0

After looking at the golang doc and confirming that Semaphore won't break with an enormous amount of permits I think a Semaphore set to Integer.MAX_VALUE is the closest to a golang WaitGroup.

The thread.join is probably more similar to how you would use WaitGroup with goroutines since it deals with the cleanup of the threads however an isolated WaitGroup just like a Semaphore is agnostic of what increments it.

CountdownLatch doesn't work because you need to know a priori how many threads you want to run and you cannot increment a CountdownLatch.

Assuming the semaphore is set to Integer.MAX_VALUE:

wg.Add(n) == semaphore.acquire(n)

wg.Done() == semaphore.release()

and in your thread where you want everything to stop:

wg.Wait() == semaphore.acquire(Integer.MAX_VALUE)

However I'm not sure all the semantics carryover so I'm not going to mark this correct for now.

Adam Gent
  • 47,843
  • 23
  • 153
  • 203
  • Why would wg.wait() == acquire(Integer.MAX_VALUE), wg.Wait() in go would block current go routine until all Add has been Done. – igonejack Apr 24 '19 at 17:38
  • Because Semaphore.acquire blocks till it can get all permits. The only way it can get all permits at Integer.MAX_VALUE is everyone else has released their permit. – Adam Gent Jul 21 '22 at 19:09
-3

No, there is no 'CountDownLatch' in Go.

sync.WaitGroup may have the 'wait task finish' feature, but this API's Add() doesn't happens-befor Done().

halfer
  • 19,824
  • 17
  • 99
  • 186
  • 5
    Please remember that we have a **[Be Nice](https://stackoverflow.com/help/be-nice)** policy on Stack Overflow; this includes not using profanity or obscenities in your posts. In the future, please keep all posts profanity-free. In the meantime, this post has been edited to keep it in line with the policies. Thanks for understanding. – Mithical Aug 06 '18 at 09:42