We can use Phaser to run concurrent tasks divided into steps.
The Phaser class can synchronize the threads at the end of each step.
In this way, no thread starts its second step until all the threads have finished the first one.
We need to initialize the Phaser class with the number of tasks that participate in the synchronization operation.
We can dynamically modify this number by increasing or decreasing it.
The following code uses the Phaser class to synchronize three concurrent tasks.
import java.io.File; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.Phaser; import java.util.concurrent.TimeUnit; public class Main { public static void main(String[] args) { Phaser phaser = new Phaser(3); FileSearch system = new FileSearch("SystemFolder", phaser); FileSearch apps = new FileSearch("AppFolder", phaser); FileSearch documents = new FileSearch("DocumentFolder", phaser); Thread systemThread = new Thread(system, "System"); systemThread.start();// w w w . jav a 2 s . c o m Thread appsThread = new Thread(apps, "Apps"); appsThread.start(); Thread documentsThread = new Thread(documents, "Documents"); documentsThread.start(); try { systemThread.join(); appsThread.join(); documentsThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("Terminated: %s\n", phaser.isTerminated()); } } class FileSearch implements Runnable { private String initPath; private List<String> results; private Phaser phaser; public FileSearch(String initPath, Phaser phaser) { this.initPath = initPath; this.phaser = phaser; results = new ArrayList<>(); } @Override public void run() { phaser.arriveAndAwaitAdvance(); System.out.printf("%s: Starting.\n", Thread.currentThread().getName()); File file = new File(initPath); if (file.isDirectory()) { directoryProcess(file); } if (!checkResults()) { return; } filterResults(); if (!checkResults()) { return; } showInfo(); phaser.arriveAndDeregister(); System.out.printf("%s: Work completed.\n", Thread.currentThread().getName()); } private void showInfo() { for (int i = 0; i < results.size(); i++) { File file = new File(results.get(i)); System.out.printf("%s: %s\n", Thread.currentThread().getName(), file.getAbsolutePath()); } phaser.arriveAndAwaitAdvance(); } private boolean checkResults() { if (results.isEmpty()) { System.out.printf("%s: Phase %d: 0 results.\n", Thread.currentThread().getName(), phaser.getPhase()); System.out.printf("%s: Phase %d: End.\n", Thread.currentThread().getName(), phaser.getPhase()); phaser.arriveAndDeregister(); return false; } else { System.out.printf(Thread.currentThread().getName()+" "+ phaser.getPhase() +" "+ results.size()); phaser.arriveAndAwaitAdvance(); return true; } } private void filterResults() { List<String> newResults = new ArrayList<>(); long actualDate = new Date().getTime(); for (int i = 0; i < results.size(); i++) { File file = new File(results.get(i)); long fileDate = file.lastModified(); if (actualDate - fileDate < TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS)) { newResults.add(results.get(i)); } } results = newResults; } private void directoryProcess(File file) { File list[] = file.listFiles(); if (list != null) { for (int i = 0; i < list.length; i++) { if (list[i].isDirectory()) { directoryProcess(list[i]); } else { fileProcess(list[i]); } } } } private void fileProcess(File file) { results.add(file.getAbsolutePath()); } }