Хотя это не идеальный сценарий для использования многопоточности, но поскольку это назначение, я помещаю одно решение, которое работает. Потоки будут выполняться последовательно, и есть несколько следует отметить:
- Текущий поток не может двигаться вперед, чтобы прочитать строку в файл до тех пор, и если его сразу предыдущий поток выполняется, как они должны читать в круговой системе мода.
- После того, как текущий поток будет выполнен, прочитав строку, он должен уведомить другую ветку еще, что поток будет ждать вечно.
Я протестировал этот код с некоторыми файлами в пакете 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<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.
}
}
Приведенный выше пример может быть изменен в соответствии с точным требованием. Здесь конструктор FileReaderRoundRobinUsingPhaser принимает количество файлов и количество строк для чтения из каждого файла.Также необходимо учитывать граничные условия.
Вам не хватает части 'wait'. Но не на месте, которое вы указываете; в * верх * метода 'run'. –
Звучит так, как будто вы ищете [Phaser] (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Phaser.html) - особенно посмотрите на 'awaitPhase' код в этой ссылке. – OldCurmudgeon
Надеюсь, вы можете легко выбрать следующий поток, чтобы иметь доступ к замку. В любом случае, если вам нужно только один поток, работающий в то время, почему у вас есть поток ... Вы должны перебрать файл, чтобы получить каждую строку. – Kazaag