java notes multi threading

10
My java notes - Multi-Threading: 1. If a thread goes to sleep it does not r elease the lock. But wait() release the lock. 2. synchronized method(){ system.out.println("heello"); } is same as : method(){ synchronized(this){ system.out.println("heello"); } } benefit of second approach is that its flexible: This way u can have more then one locks for same object( if u use some third party object for locking instead of this.) u can sync one method using obj1 and another method using obj2. 3. http://tutorials.jenkov.com/java-concurrency/thread-pools.html 4. http://www.deitel.com/articles/java_tutorials/20051126/JavaMultithreading_Tutorial_ Part4.html 5. A thread can also wake-up without being notified, interrupted, or times out. This is called spurious wake-up . Though this will occur rarely, your application must guard against spurious wake-ups.This can be done by testing a condition which can cause wake-up. If condition is not true then this wake up is spurious one. So make your thread to wait again. example: class MyThread extends Thread{ Lock lock = new Lock(); boolean signal = false; public void doWait(){ synchronized(lock){ while(!signal){ lock.wait(); } signal = false; // clear signal and continue running... ie. signal is back to initial stage. } }

Upload: ravi-gupta

Post on 02-Apr-2015

313 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Java Notes Multi Threading

 My java notes - Multi-Threading:

1.  If a thread goes to sleep it does not release the lock. But wait() release the lock.2.  synchronized method(){        system.out.println("heello");     }

     is same as :

     method(){         synchronized(this){           system.out.println("heello");        }     }benefit of second approach is that its flexible: This way u can have more then one locks for same object( if u use some third party object for locking instead of this.) u can sync one method using obj1 and another method using obj2.

3.   http://tutorials.jenkov.com/java-concurrency/thread-pools.html4.   http://www.deitel.com/articles/java_tutorials/20051126/JavaMultithreading_Tutorial_Part4.html

5. A thread can also wake-up without being notified, interrupted, or times out. This is called spurious wake-up. Though this will occur rarely, your application must guard against spurious wake-ups.This can be done by testing a condition which can cause wake-up. If condition is not true then this wake up is spurious one. So make your thread to wait again.

example:

class MyThread extends Thread{

    Lock lock = new Lock();    boolean signal = false;       public void doWait(){        synchronized(lock){            while(!signal){               lock.wait();            }            signal = false;   // clear signal and continue running...  ie. signal is back to initial stage.        }    }

    public void doNotify(){        synchronized(lock){             lock.notify();             signal = true;        }    }

6.  Database deadlocks:

    transaction1 request1 locks record1 for update operation.    transaction2 request1 locks record2 for update operation.    transaction1 request2 tries to get lock on record2 for update operation.    transaction2 request2 tries to get lock on record1 for update operation.

Page 2: Java Notes Multi Threading

7.  Deadlock prevention mechanism  -     Ordering of locks.

     If you make sure that all locks are taken in same order by any thread then deadlock can never occur. eg:

common deadlock situation:

sync(A)                             sync(B)   sync(B)                             sync(A)

make sure all thread acquire locks on this order A and then B.

   Lock time out    thread1 while waiting on B times out and release lock on A. So thread2 will get lock on A and complete its execution.

8.  BlockingQueue

This is implementation of a normal queue. Just check boundary conditions and put wait and notify. if boundary condition for an operation is reached then make it wait. And just before you are adding/removing call notifyAll. Make sure to call notifyAll only when it is actually required. notifyAll is required only at boundary conditions.

public class BlockingQueue {

    private List queue = new LinkedList();    private int limit = 10;

    public BlockingQueue(int limit){        this.limit = limit;    }

    public synchronized void enqueue(Object item)        throws InterruptedException {        while(this.queue.size() == this.limit) {            wait();        }        if(this.queue.size() == 0) {            notifyAll();        }        this.queue.add(item);    }

    public synchronized Object dequeue()        throws InterruptedException{        while(this.queue.size() == 0){            wait();        }        if(this.queue.size() == this.limit){            notifyAll();        }

        return this.queue.remove(0);    }

}

9.  Thread Pool implementation

Page 3: Java Notes Multi Threading

public class ThreadPool {        private Queue queue;    List<PoolThread> threadList = new ArrayList<PoolThread>();        public ThreadPool (int noOfThreads, int batchSize){        queue = new Queue(batchSize);        for(int i=0; i<noOfThreads; i++){            PoolThread thread = new PoolThread(queue);            thread.setName("thread "+i);            threadList.add(thread);        }                for(PoolThread thread : threadList){            thread.start();        }    }

        public void execute(List<Task> taskList){        for(int i=0; i<taskList.size(); i++){            try{                queue.enqueue(taskList.get(i));            }catch(InterruptedException ie){            }        }    }}

public class PoolThread extends Thread{        Queue queue;    String name;    PoolThread(Queue queue){        this.queue = queue;            }        public void run(){        while(true){            try{                Task task = (Task)queue.dequeue();                task.run();            }catch(InterruptedException ie){                            }        }    }

}

public class ThreadPoolTest {    private static List<Task> taskList = new ArrayList<Task>();        public static void main(String args[]){        ThreadPool pool = new ThreadPool(5, 10);        for(int i=1; i<=20; i++){            taskList.add(new Task("Task "+i));        }

Page 4: Java Notes Multi Threading

                pool.execute(taskList);    }

}

class Task implements Runnable{    String name;    public Task(String name){        this.name=name;    }    public void run(){        System.out.println(name+" executed ");    }}

To stop the ThreadPool we can call this.interrupt(); on every thread in thread pool.

10. Java5 Java.util.concurrent package Executor framework is just like thread pool.

Executor can execute tasks in async fashion.

 import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService;   public class as  {     public static void main( String[] args )     {        // create and name each runnable                     Task task1 = new Task( "task1" );        Task task2 = new Task( "task2" );        Task task3 = new Task( "task3" );                  System.out.println( "Starting thread pool" );                  ExecutorService threadExecutor = Executors.newFixedThreadPool( 3 );         // start threads and place in runnable state           threadExecutor.execute( task1 ); // start task1        threadExecutor.execute( task2 ); // start task2        threadExecutor.execute( task3 ); // start task3         threadExecutor.shutdown(); // shutdown worker threads                  System.out.println( "Threads started, main ends\n" );     } // end main  }

11. Concurrent Colloctions

List list = Collections.synchronizedList(new ArrayList());

This returns a list whose methods are all sync. But dont always rely on this because, it only sync all methods like add, get etc. individually. All individual operations are thread-safe, but sequences of operations where the control flow depends on the results of previous operations may be subject to data races. Other operations like iteration or put-if-absent still require external sync.

Page 5: Java Notes Multi Threading

synchronized(list) {     Iterator i = list.iterator(); // Must be in synchronized block         while (i.hasNext())         foo(i.next());}

Failure to follow this advice may result in non-deterministic behavior.

An example:// iteration -- contains race conditions// may require external synchronization

for (int i=0; i<list.size(); i++) {    doSomething(list.get(i));}

it is possible that at some other location some code is deleting element from list. And if the timings are bad then that delete operation would execute just after list.size(). In this case, list.get() is like to return null and doSomething() would potentially throw NPE.

How can you avoid this:

you must lock the entire List while you are iterating by wrapping it with a synchronized block, synchronizing on the list. This addresses the data race, but has further costs for concurrency, since locking the entire List while iterating could block other threads from accessing the list for a long time.

Another example:

// normal iteration -- can throw ConcurrentModificationException// may require external synchronizationfor (Iterator i=list.iterator(); i.hasNext(); ) {     doSomething(i.next());}

Iterator is used to optimize the performance of iterating.However, if one thread changes a collection while another thread is traversing it through an Iterator, the next Iterator.hasNext() or Iterator.next() call will throw ConcurrentModificationException.

Solution: same as above, synchronize whole block on list object.

Problem in synchronizing on whole list object:

Scalability describes how an application's throughput behaves as its workload and available computing resources increase. A scalable program can handle a proportionally larger workload with more processors, memory, or I/O bandwidth. Locking a shared resource for exclusive access is a scalability bottleneck -- it prevents other threads from being able to access that resource, even if idle processors are available to schedule those threads. To achieve scalability, we must eliminate or reduce our dependence on exclusive resource locks.

Final Solution:

java.util.concurrent package

use CopyOnWriteArrayList  and ConcurrentHashMap instead of Collections.synchronizedMap or Collections.synchronizedList.

However these classes should be used only if required otherwise ArrayList and HashMap are

Page 6: Java Notes Multi Threading

still widely used.

CopyOnWriteArrayList is used when traversal operation is more than write operations and when you dont want to sync traversal operation.

13. why did Sun depricated .stop() method?

Because it stopped the thread without any possibility to save data. You can simulate .stop() method following ways:

boolean letStop;void prepareForStop()void doStop()

in prepareForStop() you can save your data and set letStop variable to true. and if letStop is true then call doStop().

14. Daemon threads:

User threads are service provider threads. When the only threads running are daemon threads jvm exits. For example garbage collector.

Daemon thread should not be used to run your program. Because consider a scenario: Suppose you are writing data to a file using daemon thread and if all other threads are done then daemon thread will also stop and data on file will be left corrupted.

Daemon thread should be used in cases where abrupt termination of thread does not cause any negative impact.

Think of the JVM as a club. Daemon threads are like the bouncers, and User threads are the people. Until everyone's gone, the bouncers will stay. But once they leave, the bouncers aren't needed anymore and they leave too. That's what happens in the JVM. User threads stay until they're done, and once they're done, the JVM terminates any remaining Daemon threads.

a very good example of usage of Daemon thread:

I had a case in which my APP needed to delete some info from my DB each day. I had a thread like this:

public void run () {while (true) { //infinite loop//Delete info from db//Sleep one day}}

The thing is... when I wanted to stop my APP Server, it hanged, because the Thread was a USER thread (not daemon) and JVM does not stop until all USER threads finish executing... and my thread was in a infinite loop!

So, for practical purposes, setting the thread as DAEMON tells the JVM that it has permission to stop this thread if you are shutting down your app.

run() method for a daemon thread is typically an infinite loop that waits for service requests.

Methods are:

setDaemon(true);isDaemon();

Page 7: Java Notes Multi Threading

setDaemon should not be called after .start. If you do then it will throw java.lang.IllegalThreadStateException

15. A good point

Usually in a non threaded environment main is the last thread to finish.(thats the thread JVM creates for your program.) But if it is spawning multiple thread even though main thread is over, other threads keep running.

16. Thread.sleep(xxx )

JVM can guarantee that your thread will not wake up before xxx ms, but it is highly likely that your thread can sleep more than xxx ms.

17. Is there a way to stop a thread :

endThread(){    stop = true}

run(){  while(stop!){     ///  more code  }}

we have to do something like this.....

18. ThreadLocal :

http://www.javamex.com/tutorials/synchronization_concurrency_thread_local.shtml

When we say :myTL.set(new Integer(0));// we are basically setting this value in current                // thread's local hashmap. eg. map1.put(myTL, intVal);

---------http://www.ibm.com/developerworks/java/library/j-threads3.html

Using ThreadLocal to implement a per-thread Singleton

Thread-local variables are commonly used to render stateful Singleton or shared objects thread-safe, either by encapsulating the entire unsafe object in a ThreadLocal or by encapsulating the object's thread-specific state in a ThreadLocal. For example, in an application that is tightly tied to a database, many methods may need to access the database. It could be inconvenient to include a Connection as an argument to every method in the system -- a sloppier, but significantly more convenient technique would be to access the connection with a Singleton. However, multiple threads cannot safely share a JDBC Connection. By using a ThreadLocal in our Singleton, as shown in Listing 3, we can allow any class in our program to easily acquire a reference to a per-thread Connection. In this way, we can think of a ThreadLocal as allowing us to create a per-thread-singleton.

Listing 3. Storing a JDBC Connection in a per-thread Singleton

public class ConnectionDispenser {   private static class ThreadLocalConnection extends ThreadLocal {       public Object initialValue() {          return DriverManager.getConnection(ConfigurationSingleton.getDbUrl());

Page 8: Java Notes Multi Threading

       }   }

   private static ThreadLocalConnection conn = new ThreadLocalConnection();   public static Connection getConnection() {       return (Connection) conn.get();   }} Any stateful or non-thread-safe object that is relatively more expensive to create than to use, such as a JDBC Connection or a regular-expression matcher, is a good candidate for the per-thread-singleton technique. Of course, for situations like this, you can use other approaches, like pooling, for safely managing shared access. However, even pooling has some potential drawbacks from a scalability perspective. Because pool implementations must synchronize to maintain the integrity of the pool data structures, if all threads are using the same pool, program performance may suffer due to contention in a system with many threads accessing the pool frequently.

-----------------

An example may help clarify this concept. A servlet is executed in a thread, but since many users may use the same servlet at the same time, many threads will be running the same servlet code concurrently. If the servlet uses a ThreadLocal object, it can hold data local to each thread. The user ID is a good example of what could be stored in the ThreadLocal object.

--------------------

19. Double check locking

http://en.wikipedia.org/wiki/Double-checked_lockinghttp://www.ibm.com/developerworks/java/library/j-dcl.html

The IBM article is old one. Now from Java 1.5 onwards double check locking works well with volatile keyword. earlier versions of java did not have correct implementation of volatile keyword but 1.5 onwards it works. See head first design pattern book for reference.