You can indeed use Executors.newSingleThreadExecutor() like this :
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");
}
}
Here the executorService will run a new Runnable which just run your method calculateFactor. To ensure that factor will be updated correctly and read by the mainThread in parallel, you can use an AtomicInteger which is dedicated for this kind of job. About shutdown and interrupt, at the end you should do :
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.SECONDS); // Time is arbitrary here. It depends your need
See shutdown and awaitTermination which first call have any difference? for more details.
In your example, when I test it, factor does not change because you wait 5 seconds and the thread calculateFactor wait 5 seconds so my result is :
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
But if I put let's say cnt>10 I have this result :
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]
Hope it answers your question
Addition : if you want to run calculateFactor only once you can use countDownLatch to wait on the Thread. Example :
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");
}
}
Output will be :
starting...
Received: apple 1
Received: oranges 1
Received: bananas 1
[true, true, true]
done
More details on CountDownlLatch : https://www.baeldung.com/java-countdown-latch