Ответ 1
Вы действительно не можете улучшить, если один поток читает файл последовательно, предполагая, что вы не сделали ничего подобного полоске файла на нескольких дисках. С помощью одного потока вы выполняете поиск, а затем одно длинное последовательное чтение; с несколькими потоками вы будете иметь потоки, вызывающие несколько запросов, поскольку каждый получает контроль над головкой диска.
Изменить: это способ распараллеливать обработку строк, все еще используя последовательный ввод-вывод для чтения строк. Он использует BlockingQueue для связи между потоками; FileTask
добавляет строки в очередь, а CPUTask
считывает их и обрабатывает их. Это потокобезопасная структура данных, поэтому нет необходимости добавлять к ней какую-либо синхронизацию. Вы используете put(E e)
для добавления строк в очередь, поэтому, если очередь заполнена (она может содержать до 200 строк, как определено в объявлении в ReadingFile
), блоки FileTask
до тех пор, пока пространство не будет освобождено; Аналогично, вы используете take()
для удаления элементов из очереди, поэтому CPUTask
будет блокироваться до тех пор, пока элемент не будет доступен.
public class ReadingFile {
public static void main(String[] args) {
final int threadCount = 10;
// BlockingQueue with a capacity of 200
BlockingQueue<String> queue = new ArrayBlockingQueue<>(200);
// create thread pool with given size
ExecutorService service = Executors.newFixedThreadPool(threadCount);
for (int i = 0; i < (threadCount - 1); i++) {
service.submit(new CPUTask(queue));
}
// Wait til FileTask completes
service.submit(new FileTask(queue)).get();
service.shutdownNow(); // interrupt CPUTasks
// Wait til CPUTasks terminate
service.awaitTermination(365, TimeUnit.DAYS);
}
}
class FileTask implements Runnable {
private final BlockingQueue<String> queue;
public FileTask(BlockingQueue<String> queue) {
this.queue = queue;
}
@Override
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("D:/abc.txt"));
String line;
while ((line = br.readLine()) != null) {
// block if the queue is full
queue.put(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class CPUTask implements Runnable {
private final BlockingQueue<String> queue;
public CPUTask(BlockingQueue<String> queue) {
this.queue = queue;
}
@Override
public void run() {
String line;
while(true) {
try {
// block if the queue is empty
line = queue.take();
// do things with line
} catch (InterruptedException ex) {
break; // FileTask has completed
}
}
// poll() returns null if the queue is empty
while((line = queue.poll()) != null) {
// do things with line;
}
}
}