Java Threads 2 - PowerPoint PPT Presentation

1 / 46
About This Presentation
Title:

Java Threads 2

Description:

A thread in computer science is short for a thread of ... Singleton creation idiom. class Singleton{ private static Singleton instance; private Vector v; ... – PowerPoint PPT presentation

Number of Views:149
Avg rating:3.0/5.0
Slides: 47
Provided by: csHai
Category:
Tags: idiom | java | threads

less

Transcript and Presenter's Notes

Title: Java Threads 2


1
Java Threads 2
  • Web Programming course
  • Dan Goldwasser
  • dgoldwas_at_cs.haifa.ac.il

2
What are threads?
  • A thread in computer science is short for a
    thread of execution or a sequence of
    instructions. Multiple threads can be executed in
    parallel on many computer systems.
  • This multithreading generally occurs by time
    slicing (where a single processor switches
    between different threads) or by multiprocessing
    (where threads are executed on separate
    processors).
  • Threads are similar to processes, but differ in
    the way that they share resources.
  • (From Wikipedia, the free encyclopedia)

3
Java implementation of threads
  • We shall look at three version of thread
    instances
  • Interface Runnable
  • Class TimerTask
  • Class Thread

4
Hmmm
  • Scheduling introduces some new concepts
  • non-determinism
  • race condition
  • concurrency
  • A mechanism for synchronizing the threads could
    be useful

5
Non Determinism Example
  • class My_thread extends Threadprivate int
    field_1 0private int field_2 0public
    void run() setDaemon(true)  // this thread
    will not keep the app alive while( true
    ) System.out.println( " field_1" field_1"
    field_2" field_2 ) sleep(100)
  • synchronized public void modify( int
    new_value )
  • field_1 new_value field_2
    new_value
  • My_thread test new My_threadtest.start()//.
    ..test.modify(1)

field_10, field20field_10,
field21 field_11, field21
6
Synchronizing threads
  • So far we've seen independent, asynchronous
    threads.
  • Each thread contained all the data and methods
    required for its execution and didnt require any
    outside resources or methods.
  • The threads in those examples ran at their own
    pace without concern for the state or activities
    of any other concurrently running threads.
  • This is usually not the case, in many situations
    concurrently running threads do share data and
    must consider the state and activities of other
    threads
  • Some synchronization between the threads is
    needed

7
Producer - consumer
  • the producer generates a stream of data that a
    consumer uses
  • Because the threads share a common resource, they
    must be synchronized.

producer
consumer
8
Example 1 - producer
  • public class Producer extends Thread
  • private CubbyHole cubbyhole
  • private int number
  • public Producer(CubbyHole c, int number)
  • cubbyhole c
  • this.number number
  • public void run()
  • for (int i 0 i lt 10 i)
  • cubbyhole.put(number, i)
  • try sleep((int)(Math.random() 100))
  • catch (InterruptedException e)

9
Example 1 - consumer
  • public class Consumer extends Thread
  • private CubbyHole cubbyhole
  • private int number
  • public Consumer(CubbyHole c, int number)
  • cubbyhole c
  • this.number number
  • public void run()
  • int value 0 for (int i 0 i lt 10 i)
  • value cubbyhole.get(number)

10
Producer consumer
  • Synchronization is done by writing-reading from
    CubbyHole instance
  • Problems
  • Producer is quicker than the Consumer
  • Consumer is quicker than the Producer
  • A race condition is a situation in which two or
    more threads or processes are reading or writing
    some shared data, and the final result depends on
    the timing of how the threads are scheduled

11
Cubbyhole first attempt
  • public class CubbyHole
  • private int contents
  • private boolean available false
  • public int get(int who)
  • while (available false)
  • available false
  • System.out.println("Consumer " who "
    got " contents)
  • return contents
  • public void put(int who, int value)
  • while (available true)
  • contents value
  • available true
  • System.out.println("Producer " who "
    put " contents)

producer
consumer
12
Cubbyhole first attempt
  • public class CubbyHole
  • private int contents
  • private boolean available false
  • public int get(int who)
  • while (available false)
  • available false
  • System.out.println("Consumer " who "
    got " contents)
  • return contents
  • public void put(int who, int value)
  • while (available true)
  • contents value
  • available true
  • System.out.println("Producer " who "
    put " contents)

producer
consumer
13
synchronization
  • The Producer and the Consumer must be
    synchronized in two ways
  • The two threads must not simultaneously access
    the CubbyHole. When an object is locked by one
    thread and another thread tries to call a
    synchronized method on the same object, the
    second thread will block until the object is
    unlocked.
  • The two threads must do some simple coordination.
    That is, the Producer must have a way to indicate
    to the Consumer that the value is ready, and the
    Consumer must have a way to indicate that the
    value has been retrieved. The Object class
    provides the methods - wait, notify, and notifyAll

14
Synchronized code
  • Within a program, the code segments that access
    the same object from separate, concurrent threads
    are called critical sections
  • A critical section can be a block or a method and
    is identified with the synchronized keyword.
  • In the producer-consumer example, the put and
    get methods of CubbyHole.java are the critical
    sections. The Consumer should not access the
    CubbyHole when the Producer is changing it, and
    the Producer should not modify it when the
    Consumer is getting the value.

15
Example 2 - CubbyHole
  • public class CubbyHole
  • private int contents
  • private boolean available false
  • public synchronized int get(int who) ...
  • public synchronized void put(int who, int value)
    ...

16
Wait\Notify
  • The two threads must also be able to notify one
    another when they've done their job
  • notifyAll() - wakes up all threads waiting on the
    object in question . The awakened threads compete
    for the lock. One thread gets it, and the others
    go back to waiting
  • notify() - arbitrarily wakes up one of the
    threads waiting on this object
  • wait() - Waits indefinitely for notification.
    (This method was used in the producer-consumer
    example.)
  • wait(long timeout) - Waits for notification or
    until the timeout period has elapsed. timeout is
    measured in milliseconds.

17
Example 3 wait\notify
  • public synchronized int get()
  • while (available false)
  • try
  • //wait for Producer to put value
  • wait()
  • catch (InterruptedException e)
  • available false
  • //notify Producer that value has been
    retrieved
  • notifyAll()
  • return contents

18
Example 3 wait\notify
  • public synchronized void put(int value)
  • while (available true)
  • try
  • //wait for Consumer to get value
  • wait()
  • catch (InterruptedException e)
  • contents value
  • available true
  • //notify Consumer that value has been set
  • notifyAll()

19
Threads Pool
  • Many server applications are oriented around
    processing a large number of short tasks that
    arrive from some remote source
  • One simplistic model for building a server
    application would be to create a new thread each
    time a request arrives and service the request in
    the new thread.
  • Overhead of creating a new thread for each
    request is significant
  • Active threads consume system resources. Creating
    too many threads in one JVM can cause the system
    to run out of memory or thrash due to excessive
    memory consumption.

20
Threads Pool
  • Motivation
  • Re-use of existing threads (Thread creation is
    expensive)
  • Control the number of threads running
    concurrently (controlling Starvation)

1. Create a number of threads and add the threads
to the pool
What if There are more requests than threads ?
2. Wait for a request
t2
t2
t1
3. Assign a thread to handle the request
t4
t3
4. Return the thread to the pool
21
Threads Pool
  • public class WorkQueue
  • private final int nThreads
  • private final PoolWorker threads
  • private final LinkedList queue
  • public WorkQueue(int nThreads)
  • this.nThreads nThreads
  • queue new LinkedList()
  • threads new PoolWorkernThreads
  • for (int i0 iltnThreads i)
  • threadsi new PoolWorker()
  • threadsi.start()
  • public void execute(Runnable r)
  • synchronized(queue)
  • queue.addLast(r)
  • queue.notify()

22
private class PoolWorker extends Thread
public void run() Runnable r
while (true)
synchronized(queue) while
(queue.isEmpty()) try
queue.wait()
catch
(InterruptedException ignored)
r (Runnable)
queue.removeFirst()
// If we don't catch RuntimeException,
// the pool could leak threads
try r.run()
catch
(RuntimeException e) // You
might want to log something here

23
Risks of thread pools
  • Deadlock thread pools introduce another
    opportunity for deadlock, where all pool threads
    are executing tasks that are blocked waiting for
    the results of another task on the queue, but the
    other task cannot run because there is no
    unoccupied thread available.
  • Resource thrashing Threads consume numerous
    resources, including memory and other system
    resources. In addition, the JVM will likely
    create a native thread for each Java thread,
    which will consume additional system resources.
  • If a thread pool is too large, the
    resources consumed by those threads could have a
    significant impact on system performance.
  • Thread leakage A significant risk in all kinds of
    thread pools is thread leakage, which occurs when
    a thread is removed from the pool to perform a
    task, but is not returned to the pool when the
    task completes. One way this happens is when the
    task throws a RuntimeException or an Error. If
    the pool class does not catch these, then the
    thread will simply exit
  • Tasks that permanently stall, (potentially
    wait forever for resources or for input from
    users) can also cause the equivalent of thread
    leakage. Such tasks should either be given their
    own thread or wait only for a limited time.
  • Request overload It is possible for a server to
    simply be overwhelmed with requests. In this
    case, we may not want to queue every incoming
    request to our work queue, because the tasks
    queued for execution may consume too many system
    resources and cause resource starvation.

24
Starvation and Deadlocks
  • a program in which several concurrent threads are
    competing for resources, you must take
    precautions to ensure fairness.
  • A system is fair when each thread gets enough
    access to limited resources to make reasonable
    progress.
  • A fair system prevents starvation and deadlock ,
    starvation occurs when one or more threads in
    your program are blocked from gaining access to a
    resource and, as a result, cannot make progress.
  • Deadlock, the ultimate form of starvation, occurs
    when two or more threads are waiting on a
    condition that cannot be satisfied. Deadlock most
    often occurs when two (or more) threads are each
    waiting for the other(s) to do something

25
Dining Philosophers
How can this be solved?
26
Deadlock example
Thread T2
synchronized (y)
synchronized (x) reload (y) .
merge (x,y)
Thread T1
synchronized (x)
synchronized (y)
configure (x)
modify (x,y)




Solution Assign a numeric id value for each
resource Each thread should request dead-locks
in incremental order.
27
Summary
  • Why is synchronization between threads needed?
  • What is the producer-consumer model?
  • What is the synchronized keyword? What is being
    locked?
  • How do threads communicate?
  • What is the dining philosophers problem? Do you
    recognize a simpler version of it?

28
  • Questions?

29
Extra samples - pipes
  • import java.io.
  • public class PipedBytes extends Object
  • public static void writeStuff(OutputStream
    rawOut)
  • try
  • DataOutputStream out new DataOutputStream(
  • new BufferedOutputStream(rawOut))
  • int data 82, 105, 99, 104, 97, 114, 100,
    32,
  • 72, 121, 100, 101
  • for ( int i 0 i lt data.length i )
  • out.writeInt(datai)
  • out.flush()
  • out.close()
  • catch ( IOException x )

30
Extra samples - pipes
  • public static void readStuff(InputStream rawIn)
  • try
  • DataInputStream in new DataInputStream(
  • new BufferedInputStream(rawIn))
  • boolean eof false
  • while ( !eof )
  • try
  • int i in.readInt()
  • System.out.println("just read " i)
  • catch ( EOFException eofx )
  • eof true
  • System.out.println("Read all data from the
    pipe")
  • catch ( IOException x )
  • x.printStackTrace()

31
Extra samples - pipes
  • public static void main(String args)
  • try
  • final PipedOutputStream out
  • new PipedOutputStream()
  • final PipedInputStream in
  • new PipedInputStream(out)
  • Runnable runA new Runnable()
  • public void run()
  • writeStuff(out)
  • Thread threadA new Thread(runA, "threadA")
  • threadA.start()
  • Runnable runB new Runnable()
  • public void run()
  • readStuff(in)
  • Thread threadB new Thread(runB, "threadB")

32
The Singleton pattern
  • Ensure that only one instance of a class is
    created
  • Provide a global point of access to the object
  • Examples
  • Window managers
  • Print spoolers
  • Filesystems

33
The Singletone pattern
34
Singleton creation idiom
  • class Singleton
  • private static Singleton instance
  • private Vector v
  • private boolean inUse
  • private Singleton()
  • v new Vector()
  • v.addElement(new Object())
  • inUse true
  • public static Singleton getInstance()
  • if (instance null) //1
  • instance new Singleton() //2
  • return instance
    //3

35
This implementation is fine for a single-threaded
program
  • Ensures that only one Singleton object is ever
    created!
  • The constructor is declared private.
  • The getInstance() method creates only one object.

36
But.. for multi-threaded
  • Thread 1 calls the getInstance() method and
    determines that instance is null at //1.
  • Thread 1 enters the if block, but is preempted by
    thread 2 before executing the line at //2.
  • Thread 2 calls the getInstance() method and
    determines that instance is null at //1.
  • Thread 2 enters the if block and creates a new
    Singleton object and assigns the variable
    instance to this new object at //2.
  • Thread 2 returns the Singleton object reference
    at //3.
  • Thread 2 is preempted by thread 1.
  • Thread 1 starts where it left off and executes
    line //2 which results in another Singleton
    object being created.
  • Thread 1 returns this object at //3.

37
Thread-safe getInstance() method
  • public static synchronized Singleton
    getInstance()
  • if (instance null) //1
  • instance new Singleton() //2
  • return instance //3
  • This implementation is too expensive because you
    pay the cost of synchronization for every
    invocation of the method

38
Wrapping line 2 with synch.
  • public static Singleton getInstance()
  • if (instance null)
  • synchronized(Singleton.class)
  • instance new Singleton()
  • return instance
  • We encounter the same problem..

39
The problem..
  • Two threads can get inside of the if statement
    concurrently when instance is null
  • Note that when the second thread enters the
    synchronized block, it does not check to see if
    instance is non-null.

40
Double-checked locking
  • public static Singleton getInstance()
  • if (instance null)
  • synchronized(Singleton.class) //1
  • if (instance null) //2
  • instance new Singleton() //3
  • return instance

41
  • Thread 1 enters the getInstance() method.
  • Thread 1 enters the synchronized block at //1
    because instance is null.
  • Thread 1 is preempted by thread 2.
  • Thread 2 enters the getInstance() method.
  • Thread 2 attempts to acquire the lock at //1
    because instance is still null. However, because
    thread 1 holds the lock, thread 2 blocks at //1.
  • Thread 2 is preempted by thread 1.
  • Thread 1 executes and because instance is still
    null at //2, creates a Singleton object and
    assigns its reference to instance.
  • Thread 1 exits the synchronized block and returns
    instance from the getInstance() method.
  • Thread 1 is preempted by thread 2.
  • Thread 2 acquires the lock at //1 and checks to
    see if instance is null.
  • Because instance is non-null, a second Singleton
    object is not created and the one created by
    thread 1 is returned.

42
Out-of-order writes
  • In line //3, the code creates a Singleton object
    and initializes the variable instance to refer to
    this object.
  • The problem with this line of code is that the
    variable instance can become non-null before the
    body of the Singleton constructor executes.

43
Its happens.. JIT complilers
  • Thread 1 enters the getInstance() method.
  • Thread 1 enters the synchronized block at //1
    because instance is null.
  • Thread 1 proceeds to //3 and makes instance
    non-null, but before the constructor executes.
  • Thread 1 is preempted by thread 2.
  • Thread 2 checks to see if instance is null.
    Because it is not, thread 2 returns the instance
    reference to a fully constructed, but partially
    initialized, Singleton object.
  • Thread 2 is preempted by thread 1.
  • Thread 1 completes the initialization of the
    Singleton object by running its constructor and
    returns a reference to it.

44
instance new Singleton()
  • mem allocate() //Allocate
    memory for Singleton object.
  • instance mem //Note that
    instance is now non-null, but

  • //has not been initialized.
  • ctorSingleton(instance) //Invoke
    constructor for Singleton passing

  • instance

45
The solution
  • Accept the synchronization of a getInstance()
    method
  • Forgo synchronization and use a static field.

46
Solution
  • class Singleton
  • private Vector v
  • private boolean inUse
  • private static Singleton instance new
    Singleton()
  • private Singleton()
  • v new Vector()
  • inUse true
  • //...
  • public static Singleton getInstance()
  • return instance
Write a Comment
User Comments (0)
About PowerShow.com