The first thing you need to understand is Concurrency is not Threads!
Thread is a task - Concurrency is about how you can do it so that tasks run safely in your application. Concurrency can be challenging when some enthusiast dev tries to over-engineer a problem that is not really well managed.
Also, make note that Parallelism is not the same as Concurrency! Read more here.
The most common way is making a
Thread (read about threads
run() etc. methods) - and over time Java has come up with a very simple library class called
They are the sole handlers of how/when to run your threads (actions). You can submit a task to them, and they will run it as soon as possible. We don't really need to care about anything other than the task itself!
So a simple way to making an Executor and then submitting a task
ExecutorService executor = Executors.newCachedThreadPool(); executor.submit(()-> () -> System.out.println(MathUtils.factorial(5));
and that's it - the executor will simply run the task as it sees fit.
You can actually use this approach and keep adding more tasks, and each task will ideally be run on a separate thread.
You have a dictionary, you want to search a word "stoic" - the first thought that came to head after reading this is that "oh - yes! I will simply skip more than half of dictionary as "S" comes after the mid - and hence I will be closer to my goal
but think your sister also wanted to find the word "manic" - she tries to access the dictionary, but wait - you were using it, so she asks you "could you please give me the dictionary and you reply "I'm not done yet..."
In the best case, she waits until you are done or she steals the dictionary from your hand and runs away 😉 If she was happy to wait for you - turn the pages, and eventually you reach the location of the word.
What you can imagine is that there were two
Thread - who had a defined work and it is possible that the work might be conflicting by nature or you and your sister can do some mutually exclusive work without ever fighting.
To summarize, we have
- threads (with some action - in java we call them
- shared resources (your CPU memory just like the dictionary)
- and a manager says your mom dictates who will get the dictionary first and who will wait or if you should stop what you were doing and give the resource to your sister! (in java we call it "interrupt") - obviously every runnable can be interrupted so we always guard the threads with a notification system with
isInterruptedflag, this is very important
Now the question is shouldn't it be better that we could specify that You are using the dictionary exclusively and your sister respects this!
So, in Java the concept of
Lock came into the picture - with just two basic methods -
Please forget about the
synchronized keyword for now which every genius programmer will tell you in concurrency. This is critical that you first understand
Lock and then the fancy keyword.
So any class (the resource which can be shared eg. Account) can keep the property of this
Lock type inside and as soon as you start accessing the resource - you set it to
accountLock.lock() - now the other person can't
lock() it until you explicitly say
accountLock.unlock() stating that the task is done.
Essentially this is how you handle concurrency in simpler terms. Some more interview worthy examples are:
Producer consumer problem
- the one thread adds biscuits on the racks, other eats from the rack, if you are doing both simultaneously chances are that you won't have enough to sell!
Reader Writer problem
- A reader is reading a post and in the meanwhile another write is editing and saving it, now the reader is always confused. Think about wikipedia!
We will see how we can fix it properly - spoilers "everything is handled by locks " 😋
So - if you are clear until this point, do let me know and wait for Day-2 😄