Running threads in circular form in java

I am new to javascript multithreading and synchronization. I am trying to complete a task in which I am given 5 files, each file will be considered as one specific stream. Each stream should read one line from the file, and then transfer to the next stream and so on. When all 5 threads read the first line, then start again from line No. 1. 2 files 1, etc.

Thread ReadThread1 = new Thread(new ReadFile(0)); Thread ReadThread2 = new Thread(new ReadFile(1)); Thread ReadThread3 = new Thread(new ReadFile(2)); Thread ReadThread4 = new Thread(new ReadFile(3)); Thread ReadThread5 = new Thread(new ReadFile(4)); // starting all the threads ReadThread1.start(); ReadThread2.start(); ReadThread3.start(); ReadThread4.start(); ReadThread5.start(); 

and in ReadFile (which implements Runnable, in the run method, I try to synchronize the bufferreader object.

  BufferedReader br = null; String sCurrentLine; String filename="Source/"+files[fileno]; br = new BufferedReader(new FileReader(filename)); synchronized(br) { while ((sCurrentLine = br.readLine()) != null) { int f=fileno+1; System.out.print("File No."+f); System.out.println("-->"+sCurrentLine); br.notifyAll(); // some thing needs to be dine here i guess }} 

Need help

0
source share
2 answers

You are missing many puzzle pieces:

  • You are trying to synchronize a local object with each thread. This may not have an effect, and the JVM may even delete the entire lock operation;

  • you execute notifyAll without matching wait ;

  • the missing wait should be at the top of the run method, not at the bottom, as you indicate.

In general, I'm afraid that fixing the code at this point is beyond the scope of a single StackOverflow answer. My suggestion is to first familiarize yourself with the basic concepts: the semantics of locks in Java, how they interact with wait and notify , and the exact semantics of these methods. An Oracle tutorial on this would be a good start.

+2
source

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() { /* * Few points to be noted: * 1. Current thread cannot move ahead to read the line in the file until and unless its immediately previous thread is done as they are supposed to read in round-robin fashion. * 2. After current thread is done reading the line it must notify the other thread else that thread will wait forever. * */ 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(); /// Ensures all threads exit at the end } } } public FileReaderRoundRobinNew(int numberOfFilesToRead) { locks = new Object[numberOfFilesToRead]; int i; String fileLocation = "src/temp/"; //Initialize lock instances in array. for(i = 0; i < numberOfFilesToRead; ++i) locks[i] = new Object(); //Create threads int j; for(j=0; j<(numberOfFilesToRead-1); j++ ){ Thread linePrinterThread = new Thread(new LinePrinterJob(fileLocation + "Temp" + j,locks[j],locks[j+1])); linePrinterThread.start(); } Thread lastLinePrinterThread = new Thread(new LinePrinterJob(fileLocation + "Temp" + j,locks[numberOfFilesToRead-1],locks[0])); lastLinePrinterThread.start(); } public void startPrinting() { synchronized (locks[0]) { locks[0].notify(); } } public static void main(String[] args) { FileReaderRoundRobinNew fileReaderRoundRobin = new FileReaderRoundRobinNew(4); fileReaderRoundRobin.startPrinting(); } } 

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(); // Files will be accessed in round robin fashion but not exactly in same order always. For example it can read 4 files as 1234 then 1342 or 1243 etc. } } 

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.

+3
source

Source: https://habr.com/ru/post/986482/


All Articles