在java中以循环方式运行线程

我是java中multithreading和同步的新手。 我正在尝试实现一个任务,其中我给了5个文件,每个文件将由一个特定的线程读取。 每个线程都应从文件中读取一行,然后将执行转发到下一个线程,依此类推。 当所有5个线程读取第一行时,再次从线程1开始运行第一行。 文件1中的2,依此类推。

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(); 

在ReadFile(实现Runnable,在run方法中,我试图在bufferreader对象上进行同步)。

  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 }} 

需要帮忙

你错过了很多部分:

  • 您尝试在每个线程的本地对象上进行同步。 这可能没有任何效果,JVM甚至可以删除整个锁定操作;

  • 你执行notifyAll没有匹配的wait ;

  • 缺少的wait必须位于run方法的顶部 ,而不是在您指示的底部。

总而言之,我担心此时修复代码超出了StackOverflow的答案范围。 我的建议是首先熟悉核心概念:Java中锁的语义,它们如何与waitnotify互操作,以及这些方法的精确语义。 关于这个主题的Oracle教程将是一个很好的开始。

虽然这不是使用multithreading的理想方案,但由于这是赋值,我提出了一个有效的解决方案。 线程将按顺序执行,并且几点需要注意:

  1. 当前线程无法向前移动以读取文件中的行,直到并且除非它之前的线程完成,因为它们应该以循环方式读取。
  2. 在当前线程完成读取该行之后,它必须通知另一个线程,否则该线程将永远等待。

我用temp包中的一些文件测试了这段代码,它能够以循环方式读取这些行。 我相信Phaser也可以用来解决这个问题。

  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(); } } 

如果唯一的目标是以循环方式读取文件而不是严格按相同顺序读取文件,那么我们也可以使用Phaser。 在这种情况下,读取文件的顺序并不总是相同,例如,如果我们有四个文件(F1,F2,F3和F4),那么在第一阶段它可以将它们读作F1-F2-F3-F4但在下一个它可以将它们读作F2-F1-F4-F3。 为了完成,我仍在提出这个解决方案。

 public class FileReaderRoundRobinUsingPhaser { final List 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. } } 

可以根据具体要求修改上述示例。 这里FileReaderRoundRobinUsingPhaser的构造函数获取从每个文件读取的文件数和行数。 还需要考虑边界条件。