You should never use join() because you should not operate on threads directly. The Java designers recognized this, and added the high level concurrency library, which includes CountDownLatch and CyclicBarrier.
You use a CountDownLatch to block any number of threads until a certain number of tasks have been completed.
You use a CyclicBarrier to block a certain number of threads until that number of threads have reached the barrier.
Stephan van Hulst wrote:You should never use join() because you should not operate on threads directly. .
Thank you Stephan. What is the harm in operating on threads directly? I mean we generally call various methods on threads such as sleep(), yield(), etc. as well.
Stephan van Hulst
posted 1 year ago
Vaibhav Gargs wrote:I mean we generally call various methods on threads such as sleep(), yield(), etc. as well.
None of those methods should be called either. It's not so much that they do a lot of harm (although sleep() can do harm in certain contexts), but using them is a clear indicator that there's something wrong with your overal application design.
People tend to think about "threads" when they should be thinking about "tasks" instead. Tasks are what you want to have done. Threads just happen to be the things to do it. When people use Thread.sleep(), what they actually really want to do is "delay the completion of this task".
Let's say I have an employee working on some sort of job, and I don't want the job to be completed just yet. I don't know, maybe the customer didn't pay yet. Do I tell the employee to go to sleep, or do I tell them to work on something else?
When you call Thread.sleep(), the thread can not be used for anything else. Instead, you should submit the remainder of the task to a ScheduledExecutorService. The remainder will be finished after a certain delay, and in the mean time, the thread is free to work on other stuff.
Similarly, when you call Thread.join(), it means "wait until the thread has stopped running", but what people actually want is "wait until the task this thread was working on has completed". You convey the second meaning using tools such as latches, barriers, conditions and futures.
In high-level modern applications, you should never have any reason to use Thread or any of its methods directly. Thread.interrupt() could be an exception to this rule, but even then you probably don't have to if you're working with methods such as Future.cancel().
This may not be the greatest example, but I'll try.
Say you want to build four wheels for a car. You don't care what thread or how many are making the wheels; you just need four of them. Use a CountDownLatch.
Now say you are assembling the car from the frame. You need to attach the wheels, drop in the engine, and install the seats. Pretend that these three operations do not depend on each other. They could start and end at different times, but all three need to be done before you proceed. Use a CyclicBarrier. This is basically a fancy join operation.
All things are lawful, but not all things are profitable.