Java interview – Concurrency

1. Why is there a need for multi-threading?

Multi-threading allows your program to execute logic in parallel. For example: if you are tasked to develop an API endpoint to download a file, read from the database, run calculations, call another API, then this will be an expensive task in terms of resources and time.

  • STEP-I: Read from DB => 10 milliseconds
  • STEP-II: Run calculations => 20 milliseconds
  • STEP-III: Download a file from AWS S3 => 3 seconds
  • STEP-IV: Call Stripe API to get user’s credit card info => 2 seconds

As you can see, it will take 5+ seconds with the best-case scenario. This isn’t too bad but still, users expect a faster response than 5+ seconds. If we use multi-threading to execute these steps in parallel then we can decrease the response time significantly.

  • STEP-I: Read from DB => 10 milliseconds
  • STEP-II: Run calculations, Download a file from AWS S3, Call Stripe API to get user’s credit card info => 3 seconds

Now instead of 5+ seconds, our new response time is 3 seconds.

2. What is multi-threading?

Multi-threading is executing a series of logic in parallel. Example: a web server is using multi-threading to execute multiple requests from clients(web browsers or mobile apps) at the same time.

3. What is a thread?

A thread is an independent path of execution within a program. Many threads can run concurrently within a program, either asynchronously or synchronously.

4. What are the differences between a thread and a process?

Threads share memory among themselves. A process does not share memory.

Threads are lightweight compared to processes.

Context switching between threads is usually less expensive than between processes.

The cost of thread intercommunication is relatively low compared to that of process intercommunication.

Threads allow different tasks to be performed concurrently.

Java Multithreading
Process Vs Threads

5. How can you create a thread?

There are two ways you can create a thread. You can extend the Thread class or implement the Runnable interface. Implementing the Runnable interface is preferred by many because it allows you to implement other interfaces or extend another class.

Using the Thread class

public class MemberThread extends Thread {

	@Override
	public void run() {
		super.run();
                // coding to execute
		System.out.println("run MemberThread...");
	}
}

Using the Runnable interface

public class UserRunnable implements Runnable {

	public UserRunnable() {
		super();
		System.out.println("UserRunnable");
	}

	@Override
	public void run() {
                // code to execute
		System.out.println("running UserRunnable..");
	}
}

public class ThreadCreationDemo {

	public static void main(String[] args) {
		Thread userThread = new Thread(new UserRunnable());
		userThread.start();
		
		MemberThread memberThread = new MemberThread();
		memberThread.start();
	}

}

Result

UserRunnable
running UserRunnable..
start MemberThread...
run MemberThread...

6. What are the different statuses of a thread?

a. NEW – a new Thread instance that was not yet started via Thread.start().

b. RUNNABLE – a running thread. It is called runnable because at any given time it could be either running or waiting for the next quantum of time from the thread scheduler. A NEW thread enters the RUNNABLE state when you call Thread.start() on it.

c. RUNNING – In this state, the thread scheduler picks the thread from the ready state, and the thread is running.

c. BLOCKED – a running thread becomes blocked if it needs to enter a synchronized section but cannot do that due to another thread holding the monitor of this section.

d. WAITING – a thread enters this state if it waits for another thread to perform a particular action. For instance, a thread enters this state upon calling the Object.wait() method on a monitor it holds, or the Thread.join() method on another thread.

e. TIMED_WAITING – same as the above, but a thread enters this state after calling timed versions of Thread.sleep()Object.wait()Thread.join() and some other methods.

f. TERMINATED – a thread has completed the execution of its Runnable.run() method and terminated.

The state of a Thread can be checked using the Thread.getState() method.

Java thread life cycle
Thread Life cycle in java, Thread States in java, thread life cycle

7. What is the difference between the Runnable interface and the Callable interface?

The Runnable interface does not have a return value or to throw unchecked exceptions.

The Callable interface has a return value. It can also throw exceptions. Callable is generally used in ExecutorService instances to start an asynchronous task and then call the returned Future instance to get its value.

FutureTask<Integer> futureTask = new FutureTask<Integer>(new CustomerCallable());

Thread customerCallableStart = new Thread(futureTask);
customerCallableStart.start();

try {
	int result = futureTask.get();
	System.out.println("result: " + result);
} catch (InterruptedException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
} catch (ExecutionException e) {
	// TODO Auto-generated catch block
        e.printStackTrace();
}

8. What is context-switching?

In Context switching, the state of the thread or process is stored so that it can be restored and execution can be resumed from the same point later. Context switching enables multiple threads or processes to share the same CPU.

9. What is the difference between preemptive scheduling and time slicing?

Under preemptive scheduling, the highest priority task executes until it enters the waiting or dead states or a higher priority task comes into existence.

Under time slicing, a task executes for a predefined slice of time and then reenters the pool of ready tasks. The scheduler then determines which task should execute next, based on priority and other factors.

10. What is the difference between the start() method and the run() method?

The start() method is used to start a newly created thread, while start() internally calls run() method.

When you invoke run() directly, the execution will run on the main thread. It won’t create a new thread for you.

11. What is the difference between user threads and daemon threads?

When we create a Thread in java program, it’s known as user thread. A daemon thread runs in the background and doesn’t prevent JVM from terminating. When there are no user threads running, JVM shutdown the program and quits. A child thread created from daemon thread is also a daemon thread.

12. How can we pause the execution of a Thread for a specific time?

We can use the Thread class sleep() method to pause the execution of a thread for a duration of time. Note that this will not stop the processing of the thread, once the thread is awake from sleep, it states gets changed to runnable and based on thread scheduling, it gets executed.

13. What do you understand about Thread Priority?

Every thread has a priority, usually higher priority thread gets precedence in execution but it depends on Thread Scheduler implementation that is OS-dependent. We can specify the priority of thread but it doesn’t guarantee that higher priority thread will get executed before lower priority thread. Thread priority is an int whose value varies from 1 to 10 where 1 is the lowest priority thread and 10 is the highest priority thread.

14. How can we make sure that the main thread is the last thread to finish in Java Program?

We can use Thread join() method to make sure all the threads created by the program is dead before finishing the main function

15. How does thread communicate with each other?

When threads share resources, communication between Threads is important to coordinate their efforts. Object class wait(), notify() and notifyAll() methods allow threads to communicate about the lock status of a resource.

16. What is the difference between wait() and sleep() method?

The wait() method releases the lock but the sleep() method doesn’t.

The wait() method is defined in Object class but the sleep() method is from the Thread class.

17. Is it possible to start a thread twice?

No, we cannot restart the thread, as once a thread started and executed, it goes to the Dead state. Therefore, if we try to start a thread twice, it will give a runtime Exception “java.lang.IllegalThreadStateException”.

18. What are daemon threads?

Daemon threads are low priority threads that provide the background support and services to the user threads. Daemon thread gets automatically terminated by the JVM if the program remains with the daemon thread only, and all other user threads are ended/died. We can make a user thread a daemon thread by calling the setDaemon() method. We can only do this before the thread is starting otherwise it will throw an exception. There are two methods for daemon thread available in the Thread class.

  • public void setDaemon(boolean status): It used to mark the thread daemon thread or a user thread.
  • public boolean isDaemon(): It checks the thread is daemon or not.

19. Why Thread sleep() and yield() methods are static?

Thread sleep() and yield() methods work on the currently executing thread. So there is no point in invoking these methods on some other threads that are in a wait state. That’s why these methods are made static so that when this method is called statically, it works on the currently executing thread and avoid confusion to the programmers who might think that they can invoke these methods on some non-running threads.

20. How can we achieve thread-safety in Java?

There are several ways to achieve thread-safety in java – synchronization, atomic concurrent classes, implementing concurrent Lock interface, using the volatile keyword, using immutable classes and Thread-safe classes.

21. What is the volatile keyword in Java

It is used to mark a variable as “being stored in main memory”. More precisely that means, that every read of a volatile variable will be read from the computer’s main memory, and not from the CPU cache and that every a write happens to a volatile variable will be written to main memory, and not just to the CPU cache.

A change in a volatile variable is visible to all other threads so one variable can be used by one thread at a time.

In a multithreaded application where the threads operate on non-volatile variables, each thread may copy variables from main memory into a CPU cache while working on them, for performance reasons. If your computer contains more than one CPU, each thread may run on a different CPU. That means, that each thread may copy the variables into the CPU cache of different CPUs.

Threads may hold copies of variables from main memory in CPU caches.

With non-volatile variables, there are no guarantees about when the Java Virtual Machine (JVM) reads data from the main memory into CPU caches or writes data from CPU caches to the main memory. This can cause problems.

Using volatile is sometimes not enough. It is recommended to use synchronized to guarantee that the reading and writing of the variable are atomic.

22. Which way is more preferred – Synchronized method or Synchronized block?

The synchronized block is the more preferred way because it doesn’t lock the Object, synchronized methods lock the Object and if there are multiple synchronization blocks in the class, even though they are not related, it will stop them from execution and put them in wait state to get the lock on Object.

23. Can you synchronize a static method?

Yes, if you do you will be synchronizing the class so only one thread can enter into a synchronized static method.

24. What is Threadlocal?

The Threadlocal class enables you to create variables that can only be read and written by the same thread. Thus, even if two threads are executing the same code, and the code has a reference to the same Threadlocal variable, the two threads cannot see each other’s Threadlocal variables.

If we want to use an ExecutorService and submit a Runnable to it, using ThreadLocal will yield non-deterministic results – because we do not have a guarantee that every Runnable action for a given userId will be handled by the same thread every time it is executed.

Use it when you have some object that is not thread-safe, but you want to avoid synchronizing access to that object.

public class UserThreadLocal extends Thread {

	private static final AtomicInteger id = new AtomicInteger(0);

	ThreadLocal<String> privateName = ThreadLocal.withInitial(() -> " John--" + id.incrementAndGet());

	@Override
	public void run() {
		super.run();
		System.out.println("run..." + privateName.get());
	}
}

25. What is Java Thread Dump, How can we get Java Thread dump of a Program?

A thread dump is a list of all the threads active in the JVM, thread dumps are very helpful in analyzing bottlenecks in the application and analyzing deadlock situations. There are many ways using which we can generate Thread dump – Using Profiler, Kill -3 command, jstack tool, etc. I prefer jstack tool to generate thread dump of a program because it’s easy to use and comes with JDK installation. Since it’s a terminal-based tool, we can create a script to generate thread dump at regular intervals to analyze it later on.




Subscribe To Our Newsletter
You will receive our latest post and tutorial.
Thank you for subscribing!

required
required


Leave a Reply

Your email address will not be published.