Skip to main content

Difference between Threads and Process and static variable --- Who will create new thread for each Http Rest Request


1) Threads manage separate Stacks.

2) Heap Area (Objects/Static variables/files  etc.. keeping area) is  same for all the threads in one process. But from diffent threads of same process can not access them since referance is keeping in stack area (becouse of 1 point) and they are creating theyown object 

3) Child thread can access parent thread's variables.

4) Process means totally different program execution.

 5) First gothrough the producer and consumer problem(at last of this blog you can see the code) then, gothrough the rest Api thread senario explained below both are very same. 


...............................................................................................................

Does Spring create new thread per request in rest controllers? --> Not spring , the tomcat will create --> for more details have a look below














V.V.V.V

When new HTTP request come, A new thread will not be created for whole rest controller class, it will create a new thread from relevant mapping method in the controller so previously assigned values in the variables of the rest controller class can be accessed or updated for all of the created threads. no worries !!!!!!! 


Eg:-

  


Actions:
                    1) localhost:8080/api/employees
                                  wait until response come

                    2) localhost:8080/api/employees

                                      wait until response come

                    3) localhost:8080/api/employees 

                                  Not wait until response come



                    4) localhost:8080/api/employees



Result :





Example 2: 










            Result: 


                    when we call the api 5 time





Spring ioc-containers

http://evisioncsse.blogspot.com/2022/03/spring-ioc-containers_17.html
..........................................................



Thread Local Storage

All threads of a process share its virtual address space. The local variables of a function are unique to each thread that runs the function. However, the static and global variables are shared by all threads in the process. With thread local storage (TLS), you can provide unique data for each thread that the process can access using a global index. One thread allocates the index, which can be used by the other threads to retrieve the unique data associated with the index.

The constant TLS_MINIMUM_AVAILABLE defines the minimum number of TLS indexes available in each process. This minimum is guaranteed to be at least 64 for all systems. The maximum number of indexes per process is 1,088.

When the threads are created, the system allocates an array of LPVOID values for TLS, which are initialized to NULL. Before an index can be used, it must be allocated by one of the threads. Each thread stores its data for a TLS index in a TLS slot in the array. If the data associated with an index will fit in an LPVOID value, you can store the data directly in the TLS slot. However, if you are using a large number of indexes in this way, it is better to allocate separate storage, consolidate the data, and minimize the number of TLS slots in use.

The following diagram illustrates how TLS works. For a code example illustrating the use of thread local storage, see Using Thread Local Storage.

Diagram that shows how the T L S process works.

The process has two threads, Thread 1 and Thread 2. It allocates two indexes for use with TLS, gdwTlsIndex1 and gdwTlsIndex2. Each thread allocates two memory blocks (one for each index) in which to store the data, and stores the pointers to these memory blocks in the corresponding TLS slots. To access the data associated with an index, the thread retrieves the pointer to the memory block from the TLS slot and stores it in the lpvData local variable.

It is ideal to use TLS in a dynamic-link library (DLL). For an example, see Using Thread Local Storage in a Dynamic Link Library.

1. Overview

In this article, we will be looking at the ThreadLocal construct from the java.lang package. This gives us the ability to store data individually for the current thread – and simply wrap it within a special type of object.

2. ThreadLocal APIThe TheadLocal construct allows us to store data that will be accessible only by a specific thread.

Let's say that we want to have an Integer value that will be bundled with the specific thread:

ThreadLocal<Integer> threadLocalValue = new ThreadLocal<>();

Next, when we want to use this value from a thread we only need to call a get() or set() method. Simply put, we can think that ThreadLocal stores data inside of a map – with the thread as the key.

Due to that fact, when we call a get() method on the threadLocalValue, we will get an Integer value for the requesting thread:

threadLocalValue.set(1);
Integer result = threadLocalValue.get();

We can construct an instance of the ThreadLocal by using the withInitial() static method and passing a supplier to it:

ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 1);

To remove the value from the ThreadLocal, we can call the remove() method:

threadLocal.remove();

To see how to use the ThreadLocal properly, firstly, we will look at an example that does not use a ThreadLocal, then we will rewrite our example to leverage that construct.

3. Storing User Data in a Map

Let's consider a program that needs to store the user-specific Context data per given user id:

public class Context {
    private String userName;

    public Context(String userName) {
        this.userName = userName;
    }
}

We want to have one thread per user id. We'll create a SharedMapWithUserContext class that implements the Runnable interface. The implementation in the run() method calls some database through the UserRepository class that returns a Context object for a given userId.

Next, we store that context in the ConcurentHashMap keyed by userId:

public class SharedMapWithUserContext implements Runnable {
 
    public static Map<Integer, Context> userContextPerUserId
      = new ConcurrentHashMap<>();
    private Integer userId;
    private UserRepository userRepository = new UserRepository();

    @Override
    public void run() {
        String userName = userRepository.getUserNameForUserId(userId);
        userContextPerUserId.put(userId, new Context(userName));
    }

    // standard constructor
}

We can easily test our code by creating and starting two threads for two different userIds and asserting that we have two entries in the userContextPerUserId map:

SharedMapWithUserContext firstUser = new SharedMapWithUserContext(1);
SharedMapWithUserContext secondUser = new SharedMapWithUserContext(2);
new Thread(firstUser).start();
new Thread(secondUser).start();

assertEquals(SharedMapWithUserContext.userContextPerUserId.size(), 2);

4. Storing User Data in ThreadLocal

We can rewrite our example to store the user Context instance using a ThreadLocal. Each thread will have its own ThreadLocal instance.

When using ThreadLocal, we need to be very careful because every ThreadLocal instance is associated with a particular thread. In our example, we have a dedicated thread for each particular userId, and this thread is created by us, so we have full control over it.

The run() method will fetch the user context and store it into the ThreadLocal variable using the set() method:

public class ThreadLocalWithUserContext implements Runnable {
 
    private static ThreadLocal<Context> userContext 
      = new ThreadLocal<>();
    private Integer userId;
    private UserRepository userRepository = new UserRepository();

    @Override
    public void run() {
        String userName = userRepository.getUserNameForUserId(userId);
        userContext.set(new Context(userName));
        System.out.println("thread context for given userId: " 
          + userId + " is: " + userContext.get());
    }
    
    // standard constructor
}

We can test it by starting two threads that will execute the action for a given userId:

ThreadLocalWithUserContext firstUser 
  = new ThreadLocalWithUserContext(1);
ThreadLocalWithUserContext secondUser 
  = new ThreadLocalWithUserContext(2);
new Thread(firstUser).start();
new Thread(secondUser).start();

After running this code we'll see on the standard output that ThreadLocal was set per given thread:

thread context for given userId: 1 is: Context{userNameSecret='18a78f8e-24d2-4abf-91d6-79eaa198123f'}
thread context for given userId: 2 is: Context{userNameSecret='e19f6a0a-253e-423e-8b2b-bca1f471ae5c'}

We can see that each of the users has its own Context.

5. ThreadLocals and Thread Pools

ThreadLocal provides an easy-to-use API to confine some values to each thread. This is a reasonable way of achieving thread-safety in Java. However, we should be extra careful when we're using ThreadLocals and thread pools together.

In order to better understand the possible caveat, let's consider the following scenario:

  1. First, the application borrows a thread from the pool.
  2. Then it stores some thread-confined values into the current thread's ThreadLocal.
  3. Once the current execution finishes, the application returns the borrowed thread to the pool.
  4. After a while, the application borrows the same thread to process another request.
  5. Since the application didn't perform the necessary cleanups last time, it may re-use the same ThreadLocal data for the new request.

This may cause surprising consequences in highly concurrent applications.

One way to solve this problem is to manually remove each ThreadLocal once we're done using it. Because this approach needs rigorous code reviews, it can be error-prone.

5.1. Extending the ThreadPoolExecutor

As it turns out, it's possible to extend the ThreadPoolExecutor class and provide a custom hook implementation for beforeExecute() and afterExecute() methods. The thread pool will call the beforeExecute() method before running anything using the borrowed thread. On the other hand, it will call the afterExecute() method after executing our logic.

Therefore, we can extend the ThreadPoolExecutor class and remove the ThreadLocal data in the afterExecute() method:

public class ThreadLocalAwareThreadPool extends ThreadPoolExecutor {

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        // Call remove on each ThreadLocal
    }
}

If we submit our requests to this implementation of ExecutorService, then we can be sure that using ThreadLocal and thread pools won't introduce safety hazards for our application.

6. Conclusion

In this quick article, we were looking at the ThreadLocal construct. We implemented the logic that uses ConcurrentHashMap that was shared between threads to store the context associated with a particular userId. Next, we rewrote our example to leverage ThreadLocal to store data that is associated with a particular userId and with a particular thread.

The implementation of all these examples and code snippets can be found over on Git.


Good example for CS student from thread

Producer-Consumer solution using threads in Java

In computing, the producer-consumer problem (also known as the bounded-buffer problem) is a classic example of a multi-process synchronization problem. The problem describes two processes, the producer and the consumer, which share a common, fixed-size buffer used as a queue. 

  • The producer’s job is to generate data, put it into the buffer, and start again.
  • At the same time, the consumer is consuming the data (i.e. removing it from the buffer), one piece at a time.

Problem 
To make sure that the producer won’t try to add data into the buffer if it’s full and that the consumer won’t try to remove data from an empty buffer.

Solution 
The producer is to either go to sleep or discard data if the buffer is full. The next time the consumer removes an item from the buffer, it notifies the producer, who starts to fill the buffer again. In the same way, the consumer can go to sleep if it finds the buffer to be empty. The next time the producer puts data into the buffer, it wakes up the sleeping consumer. 
An inadequate solution could result in a deadlock where both processes are waiting to be awakened. 
Recommended Reading- Multithreading in JAVASynchronized in JAVAInter-thread Communication

Implementation of Producer Consumer Class 

  • LinkedList list – to store list of jobs in queue.
  • A Variable Capacity – to check for if the list is full or not
  • A mechanism to control the insertion and extraction from this list so that we do not insert into list if it is full or remove from it if it is empty.

Note: It is recommended to test the below program on a offline IDE as infinite loops and sleep method may lead to it time out on any online IDE  



// Java program to implement solution of producer
// consumer problem.
 
import java.util.LinkedList;
 
public class Threadexample {
    public static void main(String[] args)
        throws InterruptedException
    {
        // Object of a class that has both produce()
        // and consume() methods
        final PC pc = new PC();
 
        // Create producer thread
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run()
            {
                try {
                    pc.produce();
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
 
        // Create consumer thread
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run()
            {
                try {
                    pc.consume();
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
 
        // Start both threads
        t1.start();
        t2.start();
 
        // t1 finishes before t2
        t1.join();
        t2.join();
    }
 
    // This class has a list, producer (adds items to list
    // and consumer (removes items).
    public static class PC {
 
        // Create a list shared by producer and consumer
        // Size of list is 2.
        LinkedList<Integer> list = new LinkedList<>();
        int capacity = 2;
 
        // Function called by producer thread
        public void produce() throws InterruptedException
        {
            int value = 0;
            while (true) {
                synchronized (this)
                {
                    // producer thread waits while list
                    // is full
                    while (list.size() == capacity)
                        wait();
 
                    System.out.println("Producer produced-"
                                       + value);
 
                    // to insert the jobs in the list
                    list.add(value++);
 
                    // notifies the consumer thread that
                    // now it can start consuming
                    notify();
 
                    // makes the working of program easier
                    // to  understand
                    Thread.sleep(1000);
                }
            }
        }
 
        // Function called by consumer thread
        public void consume() throws InterruptedException
        {
            while (true) {
                synchronized (this)
                {
                    // consumer thread waits while list
                    // is empty
                    while (list.size() == 0)
                        wait();
 
                    // to retrieve the ifrst job in the list
                    int val = list.removeFirst();
 
                    System.out.println("Consumer consumed-"
                                       + val);
 
                    // Wake up producer thread
                    notify();
 
                    // and sleep
                    Thread.sleep(1000);
                }
            }
        }
    }
}

Output: 

Producer produced-0
Producer produced-1
Consumer consumed-0
Consumer consumed-1
Producer produced-2

Important Points  

  • In PC class (A class that has both produce and consume methods), a linked list of jobs and a capacity of the list is added to check that producer does not produce if the list is full.
  • In Producer class, the value is initialized as 0. 
    • Also, we have an infinite outer loop to insert values in the list. Inside this loop, we have a synchronized block so that only a producer or a consumer thread runs at a time.
    • An inner loop is there before adding the jobs to list that checks if the job list is full, the producer thread gives up the intrinsic lock on PC and goes on the waiting state.
    • If the list is empty, the control passes to below the loop and it adds a value in the list.
  • In the Consumer class, we again have an infinite loop to extract a value from the list.
    • Inside, we also have an inner loop which checks if the list is empty.
    • If it is empty then we make the consumer thread give up the lock on PC and passes the control to producer thread for producing more jobs.
    • If the list is not empty, we go round the loop and removes an item from the list.
  • In both the methods, we use notify at the end of all statements. The reason is simple, once you have something in list, you can have the consumer thread consume it, or if you have consumed something, you can have the producer produce something.
  • sleep() at the end of both methods just make the output of program run in step wise manner and not display everything all at once so that you can see what actually is happening in the program.

Exercise :  

  • Readers are advised to use if condition in place of inner loop for checking boundary conditions.
  • Try to make your program produce one item and immediately after that make the consumer consume it before any other item is produced by the producer.

Reference – https://en.wikipedia.org/wiki/Producer%E2%80%93consumer_problem

This article is contributed by Rishabh Mahrsee. If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
 




Practice Tags : 

Comments

Popular posts from this blog

Hibernate (Java) -- by jps sasadara

Observer Design Pattern & RxJava & @Async

JAVA uml Based cording <<< by jps sasadara >>>