In the world of programming one very important (and very good to know for job interviews!) concurrency. So without wasting any more time waffling about it let's delve into the world of concurrency.
What's the difference between a process and a thread?
A process is a running application. It's a lot more heavy on your computer and has its own memory location. However, a thread has a relation to the process. It uses the same memory allocation as a process, however, it is what is used to perform the main actions in the process that seem almost as if they're performing different actions at the same time.
An example of this would be your word processing unit you can perform multiple actions that seem as if they are done at the same time.
How to create a thread in Java
Creating a thread in Java is relatively easy. Take a look at the example code implemented below...
Java:
class TestMulti extends Thread{
public void run(){
System.out.println("Your new thread has been created");
}
public static void main(String args[]){
Multi Thread1 = new Multi();
Thread1.start();
}
}
So let's take a look at this, line for line...
- Line 1 - This is creating our TestMulti thread class, we're extending from the Thread class so that we're able to use it here.
- Line 2 - We create our run system that will print out that our thread has been run when this class is run/called.
- Line 3 - Just prints out that the creation worked.
- Line 5 - Creates our main method so that java knows to run the program here.
- Line 6 - Then we create a new multi-thread object by calling the Multi system and naming it 'Thread1'.
- Line 7 - We then tell the thread we created to start.
As you can see the creation of a thread in Java is not too difficult. But it is, of course, suggested you have a much deeper understanding of threading before you go mad and start creating a bunch of multi-threads for no reason.
States of a thread
Now that we've created a thread, let's understand the different states of a thread and the lifecycle of a thread. Below is the list of each thread
- New
- Runnable
- Blocked
- Timed waiting
- Terminated
So now that we know the life cycle of a list lets take a look at what they are and when the transition occurs.
NEW - This is when the thread has been created, however, the thread itself has yet to be run/started.
RUNNABLE - This is the next stage. This is when the thread has been started and is running (or waiting to be run.)
BLOCKED - This is when the thread itself has stopped and is waiting to continue. An example of this case would be that it requires an input from a user and it can't continue until the user puts in the input. This puts the thread on hold.
TIMED WAITING - This is when the thread has a waiting period. If the function it needs to do/requested to do is not completed after a period of time the thread itself will then timeout until the task is completed.
TERMINATED - This is the end of the life cycle of the thread. Once it reaches the terminated section of it the thread then ends.
Below I've included a graph to give you a better visualization idea of how the threading system works.
As you can see the new thread moves into the runnable state, then the runnable may move into the 'blocked' or 'waiting' section. Once we've moved out of those sections we then return to the runnable state and then the cycle continues until we reach the terminated state.
What is a Daemon thread?
A daemon thread is a very low priority thread that we use. It's usually used as a garbage collector for our java program. The major differences between a daemon thread and a normal thread is that...
- The program can close even if the daemon thread is running.
- Once all other threads are terminated the daemon thread is closed.
How do you create a Daemon thread?
The implementation of a Daemon thread is very similar to the creation of a normal thread. Lets take a look at the example code below.
Java:
public class DaemonThread extends Thread
{
public DaemonThreadTest(String name){
super(name);
}
- Line 1 - We create the class we'll be creating the Daemon thread in. As you can see we yet again extend the thread class
- Line 3 - We create the constructor.
- Line 4 - We create a super class for the name.
Now that we have our object creator class let's set our newly created objects as a Daemon thread.
Java:
public static void main(String[] args) {
DaemonThreadTest DaemonThreadOne = new DaemonThread("DaemonThreadOne");
DaemonThreadOne.setDaemon(true);
}
- Line 1 - Creates the main method that we'll use to run our program.
- Line 3 - This creates our new Daemon thread object under the name 'DaemonThreadOne'
- Line 5 - Then we call our newly created object followed by the '.setDaemon' this then will make our thread a Daemon thread.
What is Java memory model (JMM)?
The Java memory model (JMM) is an automatic system in which java is given a specific amount of memory to work with. It then decides how to spread this memory along with the application and attempts to dump no longer needed memory.
Let's take a look at Minecraft for example. It's given the base amount of processing power of 2GB of ram. While this is not the most powerful version of the game it still uses this and spreads out the processing power evenly through the game. This avoids it from being a computer hog and using more memory than what is actually needed.
Of course, this number will go up as more updates are added to the game, or of course if you start modding the game. But the same system continues no matter how much ram you give it, it will still do it's best to process the amount of information evenly to avoid issues.
Different states of threading
Deadlock
As we spoke about earlier in the life cycle of a thread in Java there is the chance that a thread may go into a blocked state. While this is perfectly okay in most cases, a deadlock is the bad version of this.
A deadlock is caused when two or more threads are put into a blocked state, however, the problem is that they are both blocking one another causing these threads to never actually break out of their blocked meaning they are blocked forever.
Livelock
A livelock is very similar to a deadlock but rather reversed. A livelock often occurs when multiple threads are calling one another to work. This is where the difference is between the two. A livelock never actually enters a blocked state, but rather the threads are too busy calling each other to make any more progress, meaning that the thread is running but is never really finishing.
Starvation
Starvation works with the JMM system we spoke about earlier.
Starvation occurs when a thread is not able to get enough memory to conduct the process stopping the thread from conducting the process it's supposed to do. In other words, we are starving our thread from memory.
What will happen if we don’t override run method of thread in java?
If we don't override the run method for the new thread we've created will simply mean that our newly created thread will never actually run. So if we don't call it... nothing will happen.
What is an atomic operation?
An atomic operation is when you can safely complete an operation over multiple threads, however, you must be able to get this operation to complete without using the synchronized keyword to make it work.
What are atomic classes?
Atomic classes are the classes that do all the work when using the atomic operation. It takes all the information you need it to do and it does all of the calculations and programming under the hood, keeping it a simple process for you.
The difference between an executor and an executor service
Executor
An executor is the main part of the execution process. The executor is the final step in the whole process and its main function is to execute the function it received and push it into the correct thread.
Executor Service
Unlike the executor, the executor service is the part that gets the information and passes it into the executor, this is useful in the case you need to cancel an execution from happening. You're unable to cancel an execution from happening in the executor, however, you are able to cancel it while it's in the executor service.
Differences
Executor | Executor Service |
---|
Is the main part needed to execute information into the thread. | Inputs the information into the executor. It does not run anything. |
Uses the .execute() to execute the task | Uses .submit() to submit tasks into the executor. |
Can't cancel task once it's been completed | Can use .cancel() to cancel the task. |
What are concurrent collections?
Concurrent collections is an API designed to synchronize multi-threads.