Monday, July 10, 2017

Threading

A piece of code is thread-safe if it behaves correctly when accessed by multiple threads at once. Meaning shared data is not modified by more than one thread simultaneously.

Eg. Java has two classes that are almost equivalent, StringBuffer and StringBuilder.
The difference is that StringBuffer is thread-safe (methods in StringBuffer class are synchronized), so a single instance of a StringBuffer may be used by multiple threads at once. StringBuilder is not thread-safe, and is designed as a higher-performance replacement for those cases (the vast majority) when the String is built by only one thread.

How to make a method thread-safe in Java?


public class Counter implements Runnable {
    private int count;

    public int getCount() {
        return count++;
    }

}
 

When Thread 1 accesses the method at t1, Thread 2 may not be done with the method. So the value returned to Thread 1 is the value that has not been increased.

There are different ways through which we can make our program thread safe.
1. Synchronization is the easiest and most widely used tool for thread safety in java.
2. Use of Atomic Wrapper classes from java.util.concurrent.atomic package. For example AtomicInteger.
3. Use of locks from java.util.concurrent.locks package.
4. Using thread safe collection classes, eg. ConcurrentHashMap for thread safety.
5. Using volatile keyword with variables to make every thread read the data from memory, not read from thread cache.

Method 1 - Java synchronized
JVM guarantees that synchronized code will be executed by only one thread at a time. Java keyword synchronized is used to create thread-safe code and internally it uses locks on Object or Class to make sure only one thread is executing the synchronized code.

public class Counter implements Runnable {
    private int count;

    public synchronized int getCount() {
        return count++;
    }

}

Method 2 - Atomic Wrapper Classes

public class Counter implements Runnable {
    private AtomicInteger count = new AtomicInteger(0);

    public int getCount() {
        return count.getAndIncrement();
    }

}

public class ThreadSafety {
    public static void main(String[] args) {
        Counter counter = new Counter();
        Thread t1 = new Thread(counter,"Thread1");
        Thread t2 = new Thread(counter,"Thread2");
        t1.start();
        t2.start();
    }
}
 
 
Important points about Thread-Safety in Java
1) Immutable objects are by default thread-safe because there state can not be modified once created. Since String is immutable in Java, its inherently thread-safe.
2) Read only or final variables in Java are also thread-safe in Java.
3) Locking is one way of achieving thread-safety in Java.
4) Static variables if not synchronized properly becomes major cause of thread-safety issues.
5) Example of thread-safe class in Java: Vector, Hashtable, ConcurrentHashMap, String etc.
6) Atomic operations in Java are thread-safe e.g. reading a 32 bit int from memory because its an atomic operation it can't interleave with
other thread.
7) local variables are also thread-safe because each thread has there own copy and using local variables is good way to writing thread-safe code in Java.
8) In order to avoid thread-safety issue minimize sharing of objects between multiple thread.
9) Volatile keyword in Java can also be used to instruct thread not to cache variables and read from main memory and can also instruct JVM not
to reorder or optimize code from threading perspective.

Note:- Java classes are Thread safe if you do not have instance variables. Only instance variables need to synchronize. (Instance variable are variables declared in the class and not in within its methods.)

Variables declared in the methods are thread safe as each thread creates it own program Stack and function variables are allocated in the stack. This means that variable in a methods are created for each thread, hence does not have any thread sync issues associated.

Method variables are thread-safe, class variables are not.

Multi-threading vs Multi-tasking

Thread - is a unit of a process. When we break process into pieces it is called threads.

Eg. Take an example of Ms-Word, there is one process(main process) which has sub-processes like typing, spell checker etc.

Thread usage:-
1. now a days multi-core processor is used like octa core which has 8 cores in single processor, multiple threads can run on these cores/processor at same time.
2. in async task
3. in web application, clients initiated different threads for single application

class MyThread extends Thread / implements Runnable {

 void run(){
}

}

We can not achieve multiple inheritance in case of extending Thread class, But by implementing Runnable we can provide run() method that will be required by Thread.start() method.

synchronization :- modifier applicable for methods and blocks
- used to solve inconsistency problem
- synchronized keyword creates a block of code known as criticle section.

synchronized(object){
   // statements
}
To enter into critical section, a thread needs to obtain the corresponding object's lock.

Inter-Thread Communication :- Inter-thread communication is making synchronized threads to communicate with each other.
It is a mechanism in which a thread is paused running in its critical section and another thread is allowed to enter (or lock) in the same critical section to be executed.It is implemented by following methods of Object class:

wait() : It tells the calling/current thread to give up the lock and go to sleep until some other thread enters the same monitor and calls notify().

The wait() method releases the lock prior to waiting and reacquires the lock prior to returning from the wait() method. The wait() method is actually tightly integrated with the synchronization lock, using a feature not available directly from the synchronization mechanism. In other words, it is not possible for us to implement the wait() method purely in Java: it is a native method.

General syntax for calling wait() method is like this:
synchronized( lockObject )
{
    while( ! condition )
    {
        lockObject.wait();
    }
    
    //take the action here;
}

notify() : It wakes up one single thread that called wait() on the same object. It should be noted that calling notify() does not actually give up a lock on a resource. It tells a waiting thread that that thread can wake up. However, the lock is not actually given up until the notifier’s synchronized block has completed. So, if a notifier calls notify() on a resource but the notifier still needs to perform 10 seconds of actions on the resource within its synchronized block, the thread that had been waiting will need to wait at least another additional 10 seconds for the notifier to release the lock on the object, even though notify() had been called.

General syntax for calling notify() method is like this:
synchronized(lockObject)
{
    //establish_the_condition;

    lockObject.notify();
    
    //any additional code if needed
}

notifyAll() : It wakes up all the threads that called wait() on the same object. The highest priority thread will run first in most of the situation, though not guaranteed. Other things are same as notify() method above.

General syntax for calling notify() method is like this:
synchronized(lockObject)
{
    establish_the_condition;

    lockObject.notifyAll();
}


In general, a thread that uses the wait() method confirms that a condition does not exist (typically by checking a variable) and then calls the wait() method. 

When another thread establishes the condition (typically by setting the same variable), it calls the notify() method. The wait-and-notify mechanism does not specify what the specific condition/ variable value is. It is on developer’s hand to specify the condition to be checked before calling wait() or notify().

Producer/Consumer Problem

1) Producer thread produce a new resource in every 1 second and put it in ‘taskQueue’.
2) Consumer thread takes 1 seconds to process consumed resource from ‘taskQueue’.
3) Max capacity of taskQueue is 5 i.e. maximum 5 resources can exist inside ‘taskQueue’ at any given time.
4) Both threads run infinitely.

What happens when notify() is called and no thread is waiting?

In general practice, this will not be the case in most scenarios if these methods are used correctly. Though if the notify() method is called when no other thread is waiting, notify() simply returns and the notification is lost.

Since the wait-and-notify mechanism does not know the condition about which it is sending notification, it assumes that a notification goes unheard if no thread is waiting. A thread that later executes the wait() method has to wait for another notification to occur.

join() method waits for a thread to die. In other words, it causes the currently running threads to stop executing until the thread it joins with completes its task. OR one waits(main) for the other(child) to end. If any executing thread t1 calls join() on t2 i.e; t2.join() immediately t1 will enter into waiting state until t2 completes its execution.

yield() method pauses the currently executing thread temporarily for giving a chance to the remaining waiting threads of the same priority to execute. If there is no waiting thread or all the waiting threads have a lower priority then the same thread will continue its execution. The yielded thread when it will get the chance for execution is decided by the thread scheduler whose behavior is vendor dependent. OR "yield" means to let go, to give up, to surrender.

sleep() causes the thread to definitely stop executing for a given amount of time; if no other thread or process needs to be run, the CPU will be idle (and probably enter a power saving mode).




No comments:

Post a Comment

Web Development

Design Phase:- Below all these represent different stages of the UX/UI design flow:- Wireframes represent a very basic & visual repr...