Although this is not an ideal scenario for using multithreading, but since it is a destination, I put one solution that works. Threads will execute sequentially, and there are a few notes:
- The current thread cannot move forward to read a line in a file until its immediately previous thread is executed, since they must be read cyclically.
- After the current thread finishes reading the line, it should notify the other thread yet that the thread will wait forever.
I tested this code with some files in the temp package and it was able to read the lines in loop mode. I believe that Phaser can also be used to solve this problem.
public class FileReaderRoundRobinNew { public Object[] locks; private static class LinePrinterJob implements Runnable { private final Object currentLock; private final Object nextLock; BufferedReader bufferedReader = null; public LinePrinterJob(String fileToRead, Object currentLock, Object nextLock) { this.currentLock = currentLock; this.nextLock = nextLock; try { this.bufferedReader = new BufferedReader(new FileReader(fileToRead)); } catch (FileNotFoundException e) { e.printStackTrace(); } } @Override public void run() { String currentLine; synchronized(currentLock) { try { while ( (currentLine = bufferedReader.readLine()) != null) { try { currentLock.wait(); System.out.println(currentLine); } catch(InterruptedException e) {} synchronized(nextLock) { nextLock.notify(); } } } catch (IOException e) { e.printStackTrace(); } } synchronized(nextLock) { nextLock.notify();
If the only goal is to read the files in a circular mode, and not strictly in the same order, then we can also use Phaser. In this case, the reading order of the files is not always the same, for example, if we have four files (F1, F2, F3 and F4), then in the first phase he can read them as F1-F2-F3-F4, but in the next one read them as F2-F1-F4-F3. I still put this solution to complete.
public class FileReaderRoundRobinUsingPhaser { final List<Runnable> tasks = new ArrayList<>(); final int numberOfLinesToRead; private static class LinePrinterJob implements Runnable { private BufferedReader bufferedReader; public LinePrinterJob(BufferedReader bufferedReader) { this.bufferedReader = bufferedReader; } @Override public void run() { String currentLine; try { currentLine = bufferedReader.readLine(); System.out.println(currentLine); } catch (IOException e) { e.printStackTrace(); } } } public FileReaderRoundRobinUsingPhaser(int numberOfFilesToRead, int numberOfLinesToRead) { this.numberOfLinesToRead = numberOfLinesToRead; String fileLocation = "src/temp/"; for(int j=0; j<(numberOfFilesToRead-1); j++ ){ try { tasks.add(new LinePrinterJob(new BufferedReader(new FileReader(fileLocation + "Temp" + j)))); } catch (FileNotFoundException e) { e.printStackTrace(); } } } public void startPrinting( ) { final Phaser phaser = new Phaser(1){ @Override protected boolean onAdvance(int phase, int registeredParties) { System.out.println("Phase Number: " + phase +" Registeres parties: " + getRegisteredParties() + " Arrived: " + getArrivedParties()); return ( phase >= numberOfLinesToRead || registeredParties == 0); } }; for(Runnable task : tasks) { phaser.register(); new Thread(() -> { do { phaser.arriveAndAwaitAdvance(); task.run(); } while(!phaser.isTerminated()); }).start(); } phaser.arriveAndDeregister(); } public static void main(String[] args) { FileReaderRoundRobinUsingPhaser fileReaderRoundRobin = new FileReaderRoundRobinUsingPhaser(4, 4); fileReaderRoundRobin.startPrinting();
The above example can be modified according to the exact requirement. Here, the FileReaderRoundRobinUsingPhaser constructor takes the number of files and the number of lines to read from each file. It is also necessary to consider the boundary conditions.
source share