Explaining the unexplainable.
Monique Scholtz
Transforming Geo-Data into Actionable Insights | Software Developer & Data Engineer
After doing an exciting coding bootcamp, learning how to be efficient in Python and Java, I had to learn a whole bunch of new vocabulary in order to understand what is going on. One of the last assignments was to explain concurrency by answering a few questions on this topic.?
When I saw this word for the first time, I didn't know what it meant.?I thought maybe it's a special formula on how to calculate the predicted currencies from around the world, math can do strange things. But as I continued I learned that I know more of the concept than I thought, it's basically a fancy/scary word for multi-tasking. Well if we look at how Wikipedia translate it - "In computer science, concurrency is the ability of different parts or units of a program, algorithm, or problem to be executed out-of-order or in partial order, without affecting the final outcome".?Now I don't know about you, but that explanation has the ability to over complicate things in my head. So I am going to explain this whole thing in a way that everyone can clearly understand, especially for those newbies in tech - like me.?
One simple example I would like to use is the human brain. Your brain is doing everything from managing your organs, examining your senses, thinking about what you're thinking, and even taking care of itself. Do you think your brain is dependent on other body parts? Let's say you break your arm, imagine just from breaking your arm your whole body shuts down. If that were the case, I don't think many of you would be here right now reading this.?Programming and computers operates just like our brains.
Are you ready to deep-dive in the word of concurrencies with me? Let's go slow.?A program is created by writing code in a programming language, like Java, indented to perform specific tasks, it is stored on a disk or non-volatile memory on the device. The basic needs for a program is memory and also other system recourses, just like your brain needs your heart to pump blood (oxygen) in order for it to do its job.?
Two units are playing the main role in a program, they are processes and threads. Before we zoom in and take a closer look at how things work we need to know the difference between a process and a thread. When a program is being loaded into memory along with its needed recourses, that is called a process. Processes have instances, each running independently and is isolated from other processes since they all have a separate memory addresses. Just like your liver, kidneys and lungs have their own location, doing their own thing regardless of what the other organs are doing (best-case scenario). It's obvious that this is a good thing, when one process in the program has issues or stop working the rest goes on without your whole program or device shutting down.?
A thread is the unit of execution within a process, to use an example in our body analogy, its like your brain's synapses communicating to make things work. A process can have one or more threads but a thread can't contain a process.?Like mentioned earlier, processes do their own thing, minding their own business but with threads it's different, a problem with one thread in a process will affect other threads and because of that the process will be affected too. It makes sense though, the communication won't be there for the process to do its task. Threads sound pretty sensitive to me... so why not learn more on them.
We need to get to know threads more to understand why they are the way they are.?
There are two ways of creating an instance of thread.
First to explore: provide a?Runnable?object by writing the needed code like this :?
public class HelloRunnable implements Runnable {
public void run() {
System.out.println("Hello from a thread!");
}
public static void main(String args[]) {
(new Thread(new HelloRunnable())).start();
}
}
The basic example above shows the?Runnable?object is passed to the Thread constructor, the Runnable interface defines a single method, run(), meant to contain the code executed in the thread.
Second option is Subclass Thread, the thread class itself implements Runnable, though its run method does nothing. An application can subclass Thread, providing its own implementation of run, as in the HelloThread example shown next :?
public class HelloThread extends Thread {
public void run() {
System.out.println("Hello from a thread!");
}
public static void main(String args[]) {
(new HelloThread()).start();
}
}
The one thing they both have in common is, thread.start() in order to start the new thread.?Threads have different states and can only exist in one state at a given time.
Here are the different states in a diagram:?
领英推荐
When a new thread is created, the thread is in the new state, on the starting blocks --> when the start() method is called on the thread, the thread scheduler moves it to Runnable State, here, it may get ready to run or might be running already --> whenever the join() method is called on a thread instance, the current thread executing that statement will wait for this thread to move to the Terminated state. Before the final statement is printed on the console, the program calls join() on the second thread making the first thread wait while the second thread completes its execution and is moved to the Terminated state.?
One thread that one might over-see is the daemon thread, this thread is a low-priority thread that runs in the background to perform tasks such as garbage collection. This thread in Java is also a service provider thread that provides services to the user thread. To create this deamon thread is as simple as calling the setDaemon() method.?
Ever wondered what is the Java Memory Model? Here is a clear definition I found on Gigi-global.com : "A?memory?model?that defines legal behaviours in a multi-threaded?Java?code with respect to the shared?memory. The?JMM?serves as a contract between programmers and the JVM."
In a multiprogramming?environment, more than one process may compete for a?finite set of resources. If a process request for a resource and the resource is not presently available, then the process waits for it.?Sometimes this waiting process never succeeds to get access to the resource. This waiting for resources leads to three scenarios -?Deadlock, Livelock, and Starvation.
Deadlock is when two threads are?waiting for each other and the?waiting?never ends.?
Livelock is when two or more processes continually repeat the same interaction in?response to change in the other processes?without doing any useful work.?
Starvation is when threads are?waiting for each other but not like in deadlock, they do not wait forever. At some point they get the?recourses needed to execute thread run() method.?
When it comes to the run() method, we need to override. If we fail to do this, newly created thread won't be called and nothing will happen.?
Operations on Atomic classes of Java concurrency API are executed one after the other when trying to execute the same operation from multiple threads.
Executor - The name?says it all, an object that executes submitted runnable tasks.?
ExecutorService - ExecutorService automatically provides a pool of threads and an API for?assigning tasks to it.?
Difference between the two??
The concurrent collection APIs of Java provide a range of classes that are specifically designed to deal with concurrent operations. These classes are alternatives to the java Collection Framework and provide similar functionality except with the additional support of concurrency.?
There you have it, some deeper?understanding?of what goes on in a Java program is?sometimes all we need to understand the language better and to?write better code.?
Happy coding - Monique