threads some important concepts simon lynch [email protected]
TRANSCRIPT
issues
• the Thread class & Runnable interface
• interleaving problems
• locks
• synchronization
• problems with locks
• wait & notify
the thread problem
• the Thread class & Runnable interface- start & run methods
• the problem with multiple Threads – “interleaving”- control switches from one thread to another at inconvenient times, eg...
// draw blue ovalsetColor ( blue )
fillOval( ... )
//draw green square
setColor (green )fillRect( ... )
synchronisation
• synchronisation sets up thread locks...
• locks (intrinsic lock aka monitor lock aka monitor)- stop chunks of code being interrupted so…
…stop threads interleaving
• acquiring & releasing locks (& write-back) happens automatically with synchronisation
• NB: some problems with locks (deadlock, starvation, livelock)read... docs.oracle.com/javase/tutorial/essential/concurrency/starvelive.html
• can synchronise with methods, objects (& classes - kinda)
synchronising methods
• synchronising instance methods...
• ...or static (class) methods
• careful because...
1. they synch the object they run on (may not be what you intend)
2. object references can “leak” – adding a reference to some (unsynch’d) structure before something synch’d has completed
3. you cannot synch constructors
read...http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
synchronising code blocks
public class SynchBlob2 extends AbstractBlob implements Runnable{
static Object lock = new Object();
public void run(){ display();
while( notDeadYet() ){ snooze();
synchronized(lock){ erase();
age();if( notDeadYet() ){ move();
display();}
}}
monitors
Monitors are the objects which synchronization occurs over.
Java states that...
"a thread becomes the owner of the object's monitor in one of three ways:
1.by executing a synchronized instance method of that object. 2.by executing the body of a synchronized statement that synchronizes on the object. 3.for objects of type Class, by executing a synchronized static method of that class"
NB: Only one thread at a time can own an object's monitor.
wait & notify
public class ProdCom{ private Object next; private boolean empty = true;
public synchronized Object get(){ while (empty)
{ try { wait(); } catch (InterruptedException e) {} } empty = true; notifyAll(); return next; }
public synchronized void put(Object x){ while (!empty)
{ try{ wait();
} catch (InterruptedException e) {} } empty = false; next = x; notifyAll(); }}
wait & notify
check Java API Object docs for ...• wait() & wait(long)• notify() & notifyAll()
NB:1. these methods should only be called by a thread that owns
the object's monitor
2. java says... "interrupts and spurious wakeups are possible" so wrap calls within a suitable condition
3. remember to catch the InterruptedException
also…
LinkedBlockingQueue < E > an AJProgrammers shortcut(?)
void put(E e)E take()
…and all the stuff from…
BlockingQueueQueueCollection…etc
thread pools
ExecutorService pool = Executors.newFixedThreadPool(poolSize);
while ( stillActiveJobsArriving ){ Runnable task = getNextRunnable(); pool.execute(task);}pool.shutdown(); // finish tasks then shut down
// Wait until all threads are finishpool.awaitTermination( 5, TimeUnit.SECONDS )
callableswhat if you want values from your threads/runnables?
use Callable tasks with executors & futures (easier than it seems!)
eg...public class MyTask implements Callable<SomeType>
{ @Override
public SomeType call()
{ ... blah ...
return something of SomeType
}
...
}
callables – part 2…
ExecutorService executor = ...make some ExecutorService...
Future< SomeType > future
= executor.submit(new MyTask());
...do some stuff maybe, then...
try
{ SomeType result = future.get();
...do something with result...
} catch (ExecutionException ex)
{ clean up as required }
or use FutureTask… FutureTask<SomeType> future =
new FutureTask<SomeType>(new MyTask());
executor.execute(future);
try
{ SomeType result = future.get();
...do something with result...
} catch (ExecutionException ex)
{ clean up as required }
thread pool workloading
this discussion is Java specific…
a ThreadPool has 5 worker threads and is given 20 tasks to service;each task runs a loop which performs a Thread.sleep(ms).
1. hypothesise the threading behaviour.2. how could you test your hypothesis?3. how difficult would it be to write a new threading API to provide a
different behaviour?
other issuesHow to test multi-threaded programs…… to be discussed later in lab sessions
Thread.join()• allows one thread to wait for the completion of another
someOtherThread.join(); …causes the current thread to wait until someOtherThread
terminates
https://docs.oracle.com/javase/tutorial/essential/concurrency/join.html
other issues
“happens-before”• When a statement invokes Thread.start, every statement that has
a happens-before relationship with that statement also has a happens-before relationship with every statement executed by the new thread.
• When a thread terminates and causes a Thread.join in another thread to return, then all the statements executed by the terminated thread have a happens-before relationship with all the statements following the successful join.
https://docs.oracle.com/javase/tutorial/essential/concurrency/memconsist.html
volatiles #1class Test
{ static int i = 0, j = 0;
static void one() { i++; j++; }
static void two()
{ System.out.println("i=" + i + " j=" + j); }
}
two threads t1, t2.
t1 repeatedly calls Test.one()
t1 repeatedly calls Test.two()
sometimes t2 will print values such that j > i
examples from…http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4
volatiles #2class Test
{ static int i = 0, j = 0;
static synchronized void one() { i++; j++; }
static synchronized void two()
{ System.out.println("i=" + i + " j=" + j); }
}
one way to solve the problem
examples from…http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4
volatiles #3class Test
{ static volatile int i = 0, j = 0;
static void one() { i++; j++; }
static void two()
{ System.out.println("i=" + i + " j=" + j); }
}
another way to solve the problem
volatile guarantees that access to shared values for i and j occur in the same order during execution of each thread
examples from…http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.4
threads
• • interleaving threads• memory consistency• “happens-before”• synchronising methods of a class• but object references can “leak” – adding a reference to some (unsynchronised) structure
before something synchronised has completed• locks (intrinsic lock aka monitor lock aka monitor)• acquiring & releasing locks (NB: When a thread releases a lock, happens-before established
with any subsequent acquisition of the same lock) • deadlock, starvation & livelock• implication of “static” synchronised methods• wait & notify & notifyAll• • to read...• http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html• http://docs.oracle.com/javase/tutorial/essential/concurrency/starvelive.html•