Idiom #56 Launch 1000 parallel tasks and wait for completion
Fork-join : launch the concurrent execution of procedure f with parameter i from 1 to 1000.
Tasks are independent and f(i) doesn't return any value.
Tasks need not run all at the same time, so you may use a pool.
Wait for the completion of the 1000 tasks and then print "Finished".
class Task implements Runnable {
	int i;
	Task(int i) {
		this.i = i;
	}
	@Override
	public void run() {
		f(i);
	}
}
ExecutorService executor = Executors.newFixedThreadPool(4);
for (int i = 1; i <= 1000; i++) {
	Task task = new Task(i);
	executor.submit(task);
}
executor.shutdown();
executor.awaitTermination(10L, TimeUnit.MINUTES);
System.out.println("Finished");
		
		
	size_t taskCount = 1000;
auto remainingTasks = std::latch(static_cast<std::ptrdiff_t>(taskCount));
auto f = [&remainingTasks](int i) {
  // do work
  remainingTasks.count_down();
};
std::vector<std::jthread> threads{ 10 };
for (auto i = 0; i < taskCount; i++) {
  auto& workerThread = threads[i % 10];
  if (workerThread.joinable()) {
    workerThread.join();
  }
  workerThread = std::jthread(f, i);
}
remainingTasks.wait();
std::cout << "Finished";
		
		
	int numTasks = 1000;
Task<int>[] output = new System.Threading.Tasks.Task<int>[numTasks];
for (int i = 0; i < numTasks; i++)
{
  output[i] = Task.Factory.StartNew(
                   new Func <object, int>(LongRunningOperation), 2000);
}
Task.WaitAll(output);
int LongRunningOperation(object objMs)
{
  int ms = (int)objMs;
  Thread.Sleep(ms);
  return ms;
}
		
		
	run_n_times(Fun, N) ->
    Self = self(),
    Task = fun (I) -> spawn(?MODULE, run_task_and_notify_completion, [Self, Fun, I]) end,
    lists:foreach(Task, lists:seq(1, N)),
    wait_for_n_tasks(N).
run_task_and_notify_completion(ParentPid, Fun, Arg) ->
    Fun(Arg),
    ParentPid ! done.
wait_for_n_tasks(0) ->
    io:format("Finished~n");
wait_for_n_tasks(N) when N > 0 ->
    receive
        done ->
            ok
    end,
    wait_for_n_tasks(N-1).
run_n_times(F, 1000).