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

  1. Extend Thread.

We can create a thread by extending the Java Thread and override the run() function

To start the thread we call the start() function

2. Using Runnable

Make an implementation for the Runnable interface and then create a thread by using the default Thread constructor with Runnable

II. Thread’s common methods

  1. start(): Cause the thread to begin execution
  2. 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 count
  • Increment the retrieved value by 1
  • Store value back to count

For 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

  1. t1 retrieve count
  2. t2 retrieve count
  3. t1 increments retrieved value (retrieved value is 1 now)
  4. t2 decrements retrieved value (retrieved value is -1 now)
  5. t1 store retrieved value to count (count is 1 now)
  6. t2 store 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:

  1. Using Java synchronized keyword

JVM guarantees that when we use thesynchronized 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 asyncDemo.

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 lock release.

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: AtomicLong, AtomicBoolean, AtomicReference.

4. Using Volatile

When using 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.