Thread and Thread’s basic functions in Java
I. The basic of Java Thread
According to Java docs, here is the definition of Thread
A thread is a thread of execution in a program. The Java Virtual Machine allows an application to have multiple threads of execution running concurrently.
Actually, there is a direct mapping between a JVM thread and an OS thread. Every thread has its own priority. The more prioritized, the earlier thread’s execution be performed. We also can set priority to the thread by using
thread.setPriority(priority) note that
priority is in [1, 10]
Thread mainly have 5 state
- Created: The thread’s instance is created
- Runnable: Thread ready for running
- Running: Thread is running
- Blocked: Thread is in the blocked state.
- Terminated: Thread finishes its execution.
So how to make a thread? There are two ways to create a thread
- Extend Thread.
We can create a thread by extending the Java Thread and override the
To start the thread we call the
2. Using Runnable
Make an implementation for the
Runnable interface and then create a thread by using the default
Thread constructor with
II. Thread’s common methods
- start(): Cause the thread to begin execution
- join(): When the thread join is performed, the calling thread will go into blocked state, it remains in this state until the reference thread complete.
3. sleep(): this is a static function which causes the current thread to suspend execution for a specified period. Sleeping current thread make more time available for the processor to do other execution with other threads of current application or other application. In the above example, the thread
t1 slept in 5 seconds.
4. interrupt(): this function sends a signal to a thread that it should stop what it is doing and do something else. We can decide exactly how a thread responds to an interrupt, but normally thread will be terminated.
III. Thread Interference
There is one java multiple thread question that I sometimes ask the candidate in the interview.
What output this below program will print?
Can you guess? Yes, the answer is they can print 0, 1 and -1.
But why does it happen? That is because of interferences. Interference when two or more operations running in different threads but acting in same data, interleave. You can imagine that each operation has it own sequences of steps but it’s sequences of steps overlap with other operation’s sequences.
To understand the output of the above program, let understand the operation
count ++, it include 3 steps:
- Get the value of
- Increment the retrieved value by 1
- Store value back to
count -- the steps are the same. But instead of incrementing the retrieved value, it decrements the retrieved value.
So if the processor execute the below order of steps, we will get output is -1
t1increments retrieved value (retrieved value is 1 now)
t2decrements retrieved value (retrieved value is -1 now)
t1store retrieved value to
count(count is 1 now)
t2store retrieved value to
count(count is -1 now)
With different orders, we can have different results. So, how can we avoid this situation?
IV. Thread safety, multithreading.
Thread safety in java is the process to make program safe when using multi thread. How to achieve that, how can we avoid some unexpectes state? There are different ways to archive:
- Using Java synchronized keyword
JVM guarantees that when we use the
synchronized keyword, the code will be executed by only one thread at a time. Code example:
The result of the above code is:
Thread[Thread-0,5,main] counted 1
Thread[Thread-0,5,main] counted 2
Thread[Thread-0,5,main] counted 3
Thread[Thread-1,5,main] counted 1
Thread[Thread-1,5,main] counted 2
Thread[Thread-1,5,main] counted 3
When one thread enter to the
synchronized code block of an object, it will acquire look on that object. That make other threads which try to enter that synchronized code block will be blocked. And the lock only releases when the code execution is finished.
There is another way when using
synchronized, that is using
synchronized method, like the below code:
The result is exactly the same, the difference is when we use
synchronized function, it will lock the object. Here is the object is
2. Using ReetranLock
The idea is simple, when the thread calls
countTo function, firstly, it will try to acquire the
lock. If the lock is acquired by other thread, the current thread will wait until
3. Using atomic
Go back to our example of increment and decrement value. We can avoid it by using atomicInteger
The result is always 0. That is because now the code run in sequences. But why we need sleep before showing the result. Because we want to guarantee that the execution of both functions will be done before we display.
Java also provides other types of Atomic include:
4. Using Volatile
volatile, the thread will understand that it can only use the main memory, then instead of retrieving then change and put back to main memory, the thread now will do execution in the main memory, so the
count value is guaranteed that it is always up-to-date.