They are similar in the sense that both Thread#join() and Future#get() will block until the / cllable thread completes. In the case of Thread#join() call returns when the thread dies. The result is not returned. In the case of Future#get() it will return when the called completes its task, but the executable thread does not die (usually it is part of the thread pool, so it will be available to the pool).
If these tasks that you submit to the ExecuterService are critical, it is good practice to add a shutdown application to the application that calls threadPool.shutdown() to ensure that all running threads gracefully terminate and expects threadPool.isTerminated() to become true. or waiting for threadPool.awaitTermination(max time before force shutdown) return.
source share