Not sure if this is the cause of your problem (which you do not actually explain), but since you emphasized the importance of every bot running in its own thread I must point out that calling Executor#execute
does not necessarily run its task on a background thread. Read the Javadoc; it clearly states that the given task may, or may not, run on a background thread.
If you always want to run tasks on a background thread, call the ExecutorService
methods such as submit
, invoke
, invokeAll
.
Kill your mutex
and synchronized
. Since each bot instance is updating its own member fields, and each bot instance is being run exactly once in its own thread, there is no conflict across threads.
Your BotRunner
class seems utterly redundant. The Bot
class already has a run
method. So Bot
can be declared as implementing Runnable
and serve as our task.
Your response data member field could just as well be a local variable.
public class Bot implements Runnable
{
private final Statistic statistic = null ;
void run()
{
String responseData = firstHttpCall …
this.statistic = secondHttpCall ( responseData ) ;
}
}
Simply submit your list of Bot
objects to an executor service.
If your tasks involve blocking, such as making network calls, then you likely should be using virtual threads in Java 21+ for maximum performance.
In modern Java, an executor service is AutoCloseable
. So we can use try-with-resources syntax to automatically close it.
try
(
ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor() ;
)
{
bots.forEach( executorService :: submit ) ;
}
System.out.println( "Tasks done. Executor service closed." ) ;
By the way… Never call LocalDateTime.now
. That class cannot represent a moment as it lacks the context of a time zone or offset from UTC. To track a point on the timeline, use Instant
, OffsetDateTime
, or ZonedDateTime
.