В университете дали задание, написать поискового робота, с помощью ExecutorServise, а доступ к единому индексу должен получаться с помощью Future<>. И я не могу никак додумать, что я должен сделать чтобы выполнить данное условие
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {
Path dir = FileSystems.getDefault().getPath("src\\package\\");
Map<String, List<String>> result = new HashMap<>();
ExecutorService executor = Executors.newFixedThreadPool(8);
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.java")) {
for (Path path : stream) {
CountDownLatch countDownLatch = new CountDownLatch(1);
executor.execute(() -> {
try {
synchronized (result) {
countDownLatch.countDown();
String string = Files.lines(Paths.get("src\\package\\" + path.getFileName()), StandardCharsets.UTF_8)
.collect(Collectors.joining());
String regex = "class\\s+(?<class>\\w+)\\s+(extends\\s+(?<extends>\\w+))?";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(string);
if (matcher.find()) {
String child = matcher.group("class");
String parent = matcher.group("extends");
List<String> children = result.getOrDefault(parent, new ArrayList<>());
children.addAll(Collections.singleton(child));
result.put(parent, children);
}
}
} catch (IOException e) {
e.printStackTrace();
}
});
countDownLatch.await();
}
}
executor.shutdown();
executor.awaitTermination(10, TimeUnit.MINUTES);
result.forEach((k, v) -> System.out.println(k + ": " + v));
}
}
Вот собственно, сам код, джаве только учусь, поэтому не судите строго. Буду благодарен за любую помощь.
ExecutorService помимо запуска Runnable способен исполнять Callable, которые имеют возможность возвращать результат работы потока. Этот результат оборорачивается в экземпляр интерфейса Future, который потом можно будет опросить на предмет готовности результата, получения результата и т.д. Обычно, при запуске нескольких Callable, экземпляры Future получают после вызова у инстанса ExecutorService метода submit() либо invokeAll() с последующим сохранением их в списке, анализом состояния и получением данных. Примерно вот так может выглядеть ваш код (синхронизация внутри потоков для обновления Map уже не нужна ввиду того, что результаты кладутся в мапу уже после выполнения потоков):
public static void main(String[] args) throws Exception {
Path dir = FileSystems.getDefault().getPath("src\\package\\");
ExecutorService executor = Executors.newFixedThreadPool(8);
ArrayList<Future<Map.Entry<String, String>>> futures = new ArrayList<>();
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir, "*.java")) {
for (Path path : stream) {
Future<Map.Entry<String, String>> future = executor.submit(() -> {
Map.Entry<String, String> result = null;
try {
String string = Files.lines(Paths.get("src\\package\\" + path.getFileName()), StandardCharsets.UTF_8)
.collect(Collectors.joining());
String regex = "class\\s+(?<class>\\w+)\\s+(extends\\s+(?<extends>\\w+))?";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(string);
if (matcher.find()) {
String child = matcher.group("class");
String parent = matcher.group("extends");
result = new AbstractMap.SimpleEntry<>(parent, child);
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
});
futures.add(future);
}
}
executor.shutdown();
Map<String, List<String>> result = new HashMap<>();
for (Future<Map.Entry<String, String>> future : futures) {
Map.Entry<String, String> entry = future.get();
result.merge(entry.getKey(), Collections.singletonList(entry.getValue()), (oldL, newL) -> {
List<String> list = new ArrayList<>(oldL);
list.addAll(newL);
return list;
});
}
result.forEach((k, v) -> System.out.println(k + ": " + v));
}
Сборка персонального компьютера от Artline: умный выбор для современных пользователей