31) An immutable object is always thread safe
32) How java create the monitor or lock
In Java there is no keyword to directly create a monitor. To implement a monitor, you must create a new class and use Lock and Condition classes. Lock is the interface and ReentrantLock is the main used implementation. To create a ReentrantLock, you have two constructors, a default constructor and a constructor with a boolean argument indicating if the lock is fair or not. A fair lock indicates that the threads will acquire the locks in the order they ask for. Fairness is a little heavier than default locking strategies, so use it only if you need it. To acquire the lock, you just have to use the method lock ()and unlock () to release it. The explicit locks have the same memory semantics than the synchronized blocks. So the visibility of the changes is guarantee when you use lock()/unlock() blocks.
33) What is a advantages and disadvantages to use Locking and Condition over synchronized.
With synchronized, we will not have the condition variables. If you don’t need condition variables but only locking, it will be easier to use the synchronized blocks instead of Locks.
You can create conditions using the newCondition method on the lock. A condition is a variable of type Condition. You can make the current thread wait on the condition using the await method (and its variant with timeout) and you can signal threads using signal and signalAll methods. The signalAll method wakes up all the threads waiting on the condition variable.
import
java.util.concurrent.locks.Condition;
import
java.util.concurrent.locks.Lock;
import
java.util.concurrent.locks.ReentrantLock;
//
how lock unlock use ... how await deliver the control .. and gain it by
notify all
class
LockAndReEntrantLock {
private int j = 0;
private Lock lock = new
ReentrantLock();
private
Condition cond = lock.newCondition();
public void
increment() {
j = j +
1000;
System.out.println("Current
Thread " + Thread.currentThread().getName());
System.out.println(Thread.currentThread().getName()
+
" increment j now signaling the other thread ");
for (int i =
0; i < 10; i++) {
System.out.println("Current
Thread "
+ Thread.currentThread().getName());
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
// TODO
Auto-generated catch block
e.printStackTrace();
}
}
}
public void
method1() throws InterruptedException {
//
Thread 2 wont get a chance still one finish
lock.lock();
cond.await();//
In wait state until it gets the single
increment();
lock.unlock();
}
public void
method2() {
//
lock.lock();
lock.lock();
increment();
cond.signal();
lock.unlock();
}
}
public class
LockAndReEntrantLockDemo {
public static void
main(String[] args) {
//
Cannot refer to a non-final variable obj inside an inner class
//
defined in a different method
final
LockAndReEntrantLock obj = new LockAndReEntrantLock();
Thread
thread1 = new Thread(new
Runnable() {
@Override
public void run()
{
// TODO
Auto-generated method stub
try {
obj.method1();
}
catch (InterruptedException e) {
// TODO
Auto-generated catch block
e.printStackTrace();
}
}
});
Thread
thread2 = new Thread(new
Runnable() {
@Override
public void run()
{
obj.method2();
}
});
thread2.setName("Thread2");
thread1.setName("Thread1");
thread1.start();
thread2.start();
}
}
|
34) t.sleep(); or t.yield() are actually static methods of the Thread class—they don't affect the instance t; instead they are defined to always affect the thread that's currently executing.
35) Implementing Runnable doesn't give a class the start method. You will need to create a Thread to run the runnable.
RunnableImpl runnable = new RunnableImpl ();
Thread t = new Thread(runnable);
36) What is ConcurrentHashMap and difference between ConcurrentHashMap and Collections.synchronizedMap(map)
ConcurrentHashMap allows concurrent modification of the Map from several threads without the need to block them. Collections.synchronizedMap(map) creates a blocking Map which will degrade performance, albeit ensure consistency (if used properly).
Use the second option if you need to ensure data consistency, and each thread needs to have an up-to-date view of the map. Use the first if performance is critical, and each thread only inserts data to the map, with reads happening less frequently.
The "scalability issues" for Hashtable are present in exactly the same way in Collections.synchronizedMap (Map) - they use very simple synchronization, which means that only one thread can access the map at the same time.
This is not much of an issue when you have simple inserts and lookups (unless you do it extremely intensively), but becomes a big problem when you need to iterate over the entire Map, which can take a long time for a large Map - while one thread does that, all others have to wait if they want to insert or lookup anything.
The ConcurrentHashMap uses very sophisticated techniques to reduce the need for synchronization and allow parallel read access by multiple threads without synchronization and, more importantly, provides an Iterator that requires no synchronization and even allows the Map to be modified during interation (though it makes no guarantees whether or not elements that were inserted during iteration will be returned).
37) What is Blocking Queue
A Blocking Queue is typically used to have one thread produce objects, which another thread consumes. Here is a diagram that illustrates this principle:
A BlockingQueue with one thread putting into it, and another thread taking from it.
The producing thread will keep producing new objects and insert them into the queue, until the queue reaches some upper bound on what it can contain. It's limit, in other words. If the blocking queue reaches its upper limit, the producing thread is blocked while trying to insert the new object. It remains blocked until a consuming thread takes an object out of the queue.
The consuming thread keeps taking objects out of the blocking queue, and processes them. If the consuming thread tries to take an object out of an empty queue, the consuming thread is blocked until a producing thread puts an object into the queue.
38) What is volatile and what is different between static and volatile
Static Variable: If two Threads (suppose t1 and t2) are accessing the same object and updating a variable which is declared as static then it means t1 and t2 can make their own local copy of the same object (including static variables) in their respective cache, so updation by t1 to the static variable in its local cache wont reflect in the static variable for t2 cache. Static variables are used in the Object Context where updation by one object would reflect in all the other objects of the same class but not in the Thread context where updation of one thread to the static variable will reflect the changes immediately to all the threads (in their local cache).
Volatile variable: : If two Threads(suppose t1 and t2) are accessing the same object and updating a variable which is declared as volatile then it means t1 and t2 can make their own local cache of the Object except the variable which is declared as a volatile . So the volatile variable will have only one main copy which will be updated by different threads and updation by one thread to the volatile variable will immediately reflect to the other Thread. So the volatile variable is used in the Thread context
39) What is Thread Local?
Thread Local can be considered as a scope of access, like a request scope or session scope. It's a thread scope. You can set any object in Thread Local and this object will be global and local to the specific thread which is accessing this object. Global and local!!?
Values stored in Thread Local are global to the thread, meaning that they can be accessed from anywhere inside that thread. If a thread calls methods from several classes, then all the methods can see the Thread Local variable set by other methods (because they are executing in same thread). The value need not be passed explicitly. It's like how you use global variables.
Values stored in Thread Local are local to the thread, meaning that each thread will have it's own Thread Local variable. One thread cannot access/modify other thread's Thread Local variables.
When to use Thread Local?
Consider you have a Servlet which calls some business methods. You have a requirement to generate a unique transaction id for each and every request this servlet process and you need to pass this transaction id to the business methods, for logging purpose. One solution would be passing this transaction id as a parameter to all the business methods. But this is not a good solution as the code is redundant and unnecessary.
To solve that, you can use Thread Local. You can generate a transaction id (either in Servlet or better in a filter) and set it in the Thread Local. After this, whatever the business method, that this Servlet calls, can access the transaction id from the thread local.
This Servlet might be servicing more than one request at a time. Since each request is processed in separate thread, the transaction id will be unique to each thread (local) and will be accessible from all over the thread's execution (global).
import
java.util.concurrent.atomic.AtomicLong;
public class
ThreadLocalDemoNew implements Runnable {
public static void
main(String[] args) {
ThreadLocalDemoNew
obj = new ThreadLocalDemoNew();
Thread t1 = new
Thread(obj);
Thread t2 = new
Thread(obj);
Thread t3 = new
Thread(obj);
t1.start();
t2.start();
t3.start();
}
@Override
public void run()
{
ThreadId.set(Math.random());
IAmBussinessMethod();
chainOne.ChainOneMethod();
}
public void
IAmBussinessMethod() {
System.out.println("For
Thread " + Thread.currentThread().getName()
+
" UNIQUE ID in IAmBussinessMethod() is " +
ThreadId.get());
}
}
class
chainOne {
public static void
ChainOneMethod() {
System.out.println("For
Thread " + Thread.currentThread().getName()
+
"UNIQUE ID in ChainOneMethod() is " +
ThreadId.get());
chainTwo.ChainTwoMethod();
}
}
class
chainTwo {
public static void
ChainTwoMethod() {
System.out.println("For
Thread " + Thread.currentThread().getName()
+
" UNIQUE ID in ChainTwoMethod() is " +
ThreadId.get());
}
}
class
ThreadId {
// Atomic integer
containing the next thread ID to be assigned
private static final
AtomicLong nextId = new
AtomicLong(0);
// Thread local
variable containing each thread's ID
private static final ThreadLocal
threadLocal = new ThreadLocal()
{
@Override
protected Long
initialValue() {
return nextId.getAndIncrement();
}
};
// Returns the
current thread's unique ID, assigning it if necessary
public static double get()
{
return (double) threadLocal.get();
}
public static void set(double a) {
threadLocal.set(a);
}
}
|
40) A thread pool can be described as a collection of Runnable objects (work queue) and connections of running threads. These threads are constantly running and are checking the work query for new work. If there is new work to be done they execute this Runnable. The Thread class itself provides a method, e.g. execute (Runnable r) to add a new Runnable object to the work queue.
Life cycle
1.
Get a new task to execute
2. Execute it
3. Go back to waiting for next task
2. Execute it
3. Go back to waiting for next task
Why Thread Pools?
In many server applications, we may want to process each
client request in parallel. For that matter, we can choose traditional approach
of creating one thread per request.
Disadvantage of one thread per task approach
·
The overhead of
creating a new thread for each request is significant. Server that processing
requests can spend more time and consume more system resources in creating and
destroying threads than it would processing actual client requests.
·
Creating too many
threads in one JVM can cause the system to run out of memory or thrash due to
excessive memory consumption.
41) Thread pools address two different problems: they usually provide improved performance when executing large numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and managing the resources, including threads, consumed when executing a collection of tasks. Each ThreadPoolExecutor also maintains some basic statistics, such as the number of completed tasks.
42) The Executor Framework
•The Executor framework provides a mechanism for invoking, scheduling, and executing tasks according to a set of policies
•Also provides an implementation of thread pools through the ThreadPoolExecutor class
•This provides a way to decouple task submission from task execution policy
•Makes it easy to change task execution policy
•Supports several different execution policies by default, and developers can create Executors supporting arbitrary execution policies
The Executor interface is fairly simple it describes an object, which executes Runnables
Public interface Executor {
void execute(Runnabletask )
}
|
–A class that wishes to use the Executor framework, must implement the Executor interface and provide an implementation for execute
Class
ImpExecutor implements Executor {
void
execute(Runnable t ) {
new
Thread(t).start //This executor creates a new thread for each task submitted
}
}
|
The Executor framework comes with several implementations of Executor that implement different execution policies
–execution policy determines when a task will run, it priority and other associated parameters
1.Executor.newCachedThreadPool: Creates a thread pool of unlimited size, but if threads get freed up, they are reused
2.Executor.newFixedThreadPool: Create a thread pool of fixed size, if pool is exhausted, tasks must wait till a thread becomes free
3.Executor.newSingleThreadExecutor: Creates only a single thread, tasks are executed sequentially form the queue
package
core.study.thread;
import
java.util.concurrent.ExecutorService;
import
java.util.concurrent.Executors;
public class
ExecutorDemo {
public static void
main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i =
0; i < 10; i++) {
Runnable worker = new
WorkerThread("" + i);
executor.execute(worker);
}
executor.shutdown();
while
(!executor.isTerminated()) {
//System.out.println("Processing
is still on.....");
}
System.out.println("Finished
all threads");
}
}
class
WorkerThread implements Runnable {
private
String signal;
public
WorkerThread(String s){
this.signal = s;
}
@Override
public void run()
{
System.out.println(Thread.currentThread().getName()+"
Start. Task = "+signal);
processTask();
System.out.println(Thread.currentThread().getName()+"
End.");
}
private void
processTask() {
try {
Thread.sleep(5000);
} catch
(InterruptedException e) {
e.printStackTrace();
}
}
@Override
public
String toString(){
return this.signal;
}
}
|
No comments:
Post a Comment