You can use Thread.interrupt() to tell a thread to stop. When that thread performs a some blocking operations or checks the flag it trigger it to throw an InterruptedException to either wake up the thread or stop it.
While the purpose of interrupt() is usually to stop a thread, it doesn't mean it will. The interrupt can be ignored for long periods of time or completely ignored. If it triggers an InterruptedException this can be caught and loggged (or ignored) rather than stopping the thread.
Note: For threads in an ExecutorService, interrupting a task interrupts the thread and the ExecutorService catches this by design and doesn't shutdown the thread.