Вы действительно можете использовать Executors.newSingleThreadExecutor () вот так:
public class App {
private List<String> workItems;
private AtomicInteger factor = new AtomicInteger(0);
public App() {
workItems = new ArrayList<>();
//create some work in workItmes
workItems.add("apple");
workItems.add("oranges");
workItems.add("bananas");
}
public List<String> getWorkItems() {
return workItems;
}
public void calculateFactor() throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
factor.set(1);
}
public boolean evaluateItem(String item, int factor) {
// do some work based on item and current factor
System.out.println("Received: " + item + " " + factor);
return true;
}
public AtomicInteger getFactor() {
return factor;
}
public static void main(String[] args) throws Exception {
App myApp = new App();
ExecutorService executorService = Executors.newSingleThreadExecutor();
System.out.println("starting...");
int cnt = 0;
while (true) {
cnt++;
if (cnt > 5) {
break;
}
executorService.submit(() -> {
try {
myApp.calculateFactor();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Error when calculating Factor");
}
});
int currentFactor = myApp.getFactor().get();
List<Boolean> results = myApp.getWorkItems().stream().map(s -> myApp.evaluateItem(s, currentFactor)).collect(toList());
System.out.println(results);
TimeUnit.SECONDS.sleep(1);
}
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.SECONDS);
System.out.println("done");
}
}
Здесь executorService запустит новый Runnable, который просто запустит ваш метод CalculateFactor. Чтобы гарантировать, что factor будет корректно обновляться и параллельно считываться mainThread, вы можете использовать AtomicInteger, который предназначен для этого вида работы. Что касается отключения и прерывания, в конце вы должны сделать:
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.SECONDS); // Time is arbitrary here. It depends your need
См. shutdown и awaitTermination, какой первый вызов имеет какую-либо разницу? для получения более подробной информации.
В вашем примере, когда я проверяю его, коэффициент не меняется, потому что вы ждете 5 секунд, а поток calcFactor ждет 5 секунд, поэтому мой результат:
starting...
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
done
Но если я поставлю, скажем, cnt> 10, у меня будет такой результат:
starting...
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 0
Received: oranges 0
Received: bananas 0
[true, true, true]
Received: apple 1
Received: oranges 1
Received: bananas 1
[true, true, true]
Received: apple 1
Received: oranges 1
Received: bananas 1
[true, true, true]
Received: apple 1
Received: oranges 1
Received: bananas 1
[true, true, true]
Received: apple 1
Received: oranges 1
Received: bananas 1
[true, true, true]
Received: apple 1
Received: oranges 1
Received: bananas 1
[true, true, true]
Надеюсь, что он отвечает на ваш вопрос
Добавление: , если вы хотите запускать CalculateFactor только один раз, когда вы можете использовать countDownLatch для ожидания в потоке. Пример:
public class App {
private List<String> workItems;
private AtomicInteger factor = new AtomicInteger(0);
private CountDownLatch countDownLatch = new CountDownLatch(1);
public App() {
workItems = new ArrayList<>();
//create some work in workItmes
workItems.add("apple");
workItems.add("oranges");
workItems.add("bananas");
}
public List<String> getWorkItems() {
return workItems;
}
public CountDownLatch getCountDownLatch() {
return countDownLatch;
}
public void calculateFactor() throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
factor.set(1);
countDownLatch.countDown();
}
public boolean evaluateItem(String item, int factor) {
// do some work based on item and current factor
System.out.println("Received: " + item + " " + factor);
return true;
}
public AtomicInteger getFactor() {
return factor;
}
public static void main(String[] args) throws Exception {
App myApp = new App();
ExecutorService executorService = Executors.newSingleThreadExecutor();
System.out.println("starting...");
executorService.submit(() -> {
try {
myApp.calculateFactor();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Error when calculating Factor");
}
});
myApp.getCountDownLatch().await();
int currentFactor = myApp.getFactor().get();
List<Boolean> results = myApp.getWorkItems().stream().map(s -> myApp.evaluateItem(s, currentFactor)).collect(toList());
System.out.println(results);
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.SECONDS);
System.out.println("done");
}
}
Вывод будет:
starting...
Received: apple 1
Received: oranges 1
Received: bananas 1
[true, true, true]
done
Подробнее о CountDownlLatch: https://www.baeldung.com/java-countdown-latch