Java thread parked state

Difference Between Wait And Park Methods In Java Thread

If you are familiar with thread dump or at least looked at it couple of times, probably you would have noticed WAITING & WAITING (parking) states. So what’s the difference?

In Java, we have Object.wait() and Unsafe.park() methods. Both of them will suspend the running thread & put it in waiting state. But these two methods work on different principles. Object.wait() results in WAITING state whereas Unsafe.park() method results in WAITING (parking) state.

To understand the difference, let’s first understand the concept of two things.

Monitor: It is a construct which works on lock. Monitor can acquire a lock or give up an already acquired lock. It can also listen to a particular lock & get notification when it is released.

Happens-before relationship:

Take a look at the picture above. We have multicore CPUs nowadays. Each CPU core can work as standalone processing unit. Each CPU has its own cache where it can put frequently accessed data. Main memory or RAM is common for all CPU cores. Now JVM will utilize multiple cores when multiple threads are used for concurrency. Let’s take an example scenario.

  • Thread 1 uses core 1.
  • Thread 2 uses core 2.
  • Thread 1 & thread 2 share a common variable.
  • Core 1 will have its own copy of the variable in cache which is used by thread 1.
  • Same way, core 2 will have its own copy of the variable in its own CPU cache for thread 2.
  • Now thread 1 updates the variable & core 1 updates its own cache.
  • Thread 2 then reads the variable. But it will read from core 2 CPU cache. So thread 2 will get stale value.
Читайте также:  Python guess the number

The problem is that one CPU core doesn’t know that copy of the same variable is getting used in another CPU core. They are updating their own copy of the data & be happy with it. To avoid this, Java uses happens-before relationship. The problem here is that thread 1 didn’t update the value in main memory & thread 2 didn’t fetch the value from main memory before reading. Happens-before relationship makes sure that updated value gets synced to main memory before thread 1 releases the lock. Also thread 2 syncs the value from main memory after it acquires the lock. But this comes with additional overhead.

Object.wait():

Object.wait() method works on monitor based synchronization. And it satisfies happens-before relationship in Java.

 Object obj = new Object(); synchronized(obj) < // monitor acquires lock on object try < obj.wait(); >catch(InterruptedException e) < e.printStackTrace(); >>

Before we call a wait() method on an object, monitor needs to acquire a lock on that object. We have created a object name obj above. Monitor acquires a lock on obj in second line. Now we call wait() method on obj object. Below things happen under the hood.

  • Monitor releases the lock on obj object.
  • Thread goes to waiting state.
  • Monitor keeps on listening to locking related events on obj object.

How to bring back thread from waiting to running state:

Monitor in another thread acquires lock on obj object. It calls notify() method on obj. When notify() is called, below things happen under the hood:

  • lock on obj is released from the other thread.
  • Monitor in first thread gets notification that lock is released on obj object.
  • Monitor in first thread now acquires the lock back on obj & brings back the thread in running state.

Unsafe.park()
 sun.misc.Unsafe unsafe = null; try < java.lang.reflect.Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); unsafe = (sun.misc.Unsafe) f.get(null); >catch(NoSuchFieldException | IllegalAccessException e) < e.printStackTrace(); >unsafe.park(true, 0L);

unsafe.park() method puts the thread in waiting state. But it works on permit basis, not on monitor basis. It doesn’t satisfy happens-before relationship. You can consider permit as a counter. When park() is called, counter is incremented. Thread is put to WAITING (parking) state.

How to bring back thread from waiting(parking) to running state:

 sun.misc.Unsafe unsafe = null; try < java.lang.reflect.Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); unsafe = (sun.misc.Unsafe) f.get(null); >catch(NoSuchFieldException | IllegalAccessException e) < e.printStackTrace(); >unsafe.unpark(thread);

To decrement the counter unsafe.unpark() method needs to be called from another thread. unpark() takes a thread object as argument. Once counter becomes zero, the waiting thread passed as method argument is brought back to running state. If unpark() is called before park() method, next park() method will get unblocked immediately.

Unsafe.park() method should give better performance as it uses native code & no synchronization is required with main memory. That’s why thread pool in general (for example ExecutorService) use park method while waiting for tasks from the blocking queue. But Unsafe class is JVM specific which uses native code. As an application developer you should avoid it. Also it doesn’t guarantee happens before relationship which is required almost all the times. So stick to Object.wait().

Источник

Java Threads

Typically, we can define threads as a subprocess with lightweight with the smallest unit of processes and also has separate paths of execution. These threads use shared memory but they act independently hence if there is an exception in threads that do not affect the working of other threads despite them sharing the same memory.

Threads in a Shared Memory Environment in OS

Threads in a Shared Memory Environment in OS

As we can observe in, the above diagram a thread runs inside the process and there will be context-based switching between threads there can be multiple processes running in OS, and each process again can have multiple threads running simultaneously. The Multithreading concept is popularly applied in games, animation…etc.

The Concept Of Multitasking

To help users Operating System accommodates users the privilege of multitasking, where users can perform multiple actions simultaneously on the machine. This Multitasking can be enabled in two ways:

1. Process-Based Multitasking (Multiprocessing)

In this type of Multitasking, processes are heavyweight and each process was allocated by a separate memory area. And as the process is heavyweight the cost of communication between processes is high and it takes a long time for switching between processes as it involves actions such as loading, saving in registers, updating maps, lists, etc.

2. Thread-Based Multitasking

As we discussed above Threads are provided with lightweight nature and share the same address space, and the cost of communication between threads is also low.

Why Threads are used?

Now, we can understand why threads are being used as they had the advantage of being lightweight and can provide communication between multiple threads at a Low Cost contributing to effective multi-tasking within a shared memory environment.

Life Cycle Of Thread

There are different states Thread transfers into during its lifetime, let us know about those states in the following lines: in its lifetime, a thread undergoes the following states, namely:

  1. New State
  2. Active State
  3. Waiting/Blocked State
  4. Timed Waiting State
  5. Terminated State

Life Cycle Of Thread

We can see the working of different states in a Thread in the above Diagram, let us know in detail each and every state:

1. New State

By default, a Thread will be in a new state, in this state, code has not yet been run and the execution process is not yet initiated.

2. Active State

A Thread that is a new state by default gets transferred to Active state when it invokes the start() method, his Active state contains two sub-states namely:

  • Runnable State: In This State, The Thread is ready to run at any given time and it’s the job of the Thread Scheduler to provide the thread time for the runnable state preserved threads. A program that has obtained Multithreading shares slices of time intervals which are shared between threads hence, these threads run for some short span of time and wait in the runnable state to get their schedules slice of a time interval.
  • Running State: When The Thread Receives CPU allocated by Thread Scheduler, it transfers from the “Runnable” state to the “Running” state. and after the expiry of its given time slice session, it again moves back to the “Runnable” state and waits for its next time slice.

3. Waiting/Blocked State

If a Thread is inactive but on a temporary time, then either it is a waiting or blocked state, for example, if there are two threads, T1 and T2 where T1 needs to communicate to the camera and the other thread T2 already using a camera to scan then T1 waits until T2 Thread completes its work, at this state T1 is parked in waiting for the state, and in another scenario, the user called two Threads T2 and T3 with the same functionality and both had same time slice given by Thread Scheduler then both Threads T1, T2 is in a blocked state. When there are multiple threads parked in a Blocked/Waiting state Thread Scheduler clears Queue by rejecting unwanted Threads and allocating CPU on a priority basis.

4. Timed Waiting State

Sometimes the longer duration of waiting for threads causes starvation, if we take an example like there are two threads T1, T2 waiting for CPU and T1 is undergoing a Critical Coding operation and if it does not exist the CPU until its operation gets executed then T2 will be exposed to longer waiting with undetermined certainty, In order to avoid this starvation situation, we had Timed Waiting for the state to avoid that kind of scenario as in Timed Waiting, each thread has a time period for which sleep() method is invoked and after the time expires the Threads starts executing its task.

5. Terminated State

A thread will be in Terminated State, due to the below reasons:

  • Termination is achieved by a Thread when it finishes its task Normally.
  • Sometimes Threads may be terminated due to unusual events like segmentation faults, exceptions…etc. and such kind of Termination can be called Abnormal Termination.
  • A terminated Thread means it is dead and no longer available.

What is Main Thread?

As we are familiar, we create Main Method in each and every Java Program, which acts as an entry point for the code to get executed by JVM, Similarly in this Multithreading Concept, Each Program has one Main Thread which was provided by default by JVM, hence whenever a program is being created in java, JVM provides the Main Thread for its Execution.

How to Create Threads using Java Programming Language?

We can create Threads in java using two ways, namely :

1. By Extending Thread Class

We can run Threads in Java by using Thread Class, which provides constructors and methods for creating and performing operations on a Thread, which extends a Thread class that can implement Runnable Interface. We use the following constructors for creating the Thread:

  • Thread
  • Thread(Runnable r)
  • Thread(String name)
  • Thread(Runnable r, String name)

Sample code to create Threads by Extending Thread Class:

Источник

Оцените статью