Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Practice Session 8 • • • • • Blocking queues Producers-Consumers pattern Semaphore Futures and Callables Advanced Thread Synchronization Methods • CountDownLatch • Thread cancellation: • • • Stop shouldStop Interrupt Blocking Queues • An ordinary queue with a special feature. • The queue behaves differently in two cases: – Empty queue case • Thread wants to pop head element of the queue. • Thread is blocked until the queue stops being empty – Full queue case • Thread wants to add an element to the queue. • Thread is blocked until the queue stops being full Java Blocking Queue • API: – Package java.util.concurrent – Interface: BlockingQueue<E> • “Our” Implementation: – class MyBlockingQueue<E> implements BlockingQueue<E> • Java’s Implementation: – Java.util.concurrent.ArrayBlockingQueue<E> • Functions: – void put(E o) • Adds the specified element to this queue, waiting if necessary for space to become available. – E take() • Retrieves and removes the head of this queue, waiting if no elements are present on this queue. • API Website: – – http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ArrayBlockingQueue.html MyBlockingQueue • Private Fields: private ArrayList<E> fList; • The queue object. • Not synchronized. private final int fMax; • Our queue’s maximum size. • Received upon construction. • Fixed Size. • Constructor: MyBlockingQueue(int max){ fList = new ArrayList(); fMax = max; } • Private Functions: private synchronized int getSize(){ return fList.size(); } My Blocking Queue – put() put public synchronized void (E obj){ while(getSize()>=fMax){ try{ this.wait(); } catch (InterruptedException ignored){} } fList.add(obj); // wakeup everybody. If someone is waiting in the get() // method, it can now perform the get. this.notifyAll(); } MyBlockingQueue – take() take public synchronized E (){ while(size()==0){ try{ this.wait(); } catch (InterruptedException ignored){} } E obj = fList.get(0); fList.remove(0); // wakeup everybody. If someone is waiting in the add() // method, it can now perform the add. this.notifyAll(); return obj; } The Producer-Consumer Problem • A classical multi-process (thread) synchronization problem. • Uses a bounded (fixed-size) queue. • Two major groups: – Producer(s): • A Thread that generates new objects • Adds them to shared space – Consumer(s): • A Thread that removes objects from shared space. • Uses them. • Full queue: – A producer thread is blocked, until a free space is available. • Empty queue: – A consumer thread is blocked, until the queue receives new object. Producer-Consumer Implementation • Using ArrayBlockingQueue • Three Classes: – Producer implements Runnable – Consumer implements Runnable – Driver class (includes main function) • Code Example: – Producer-Consumer • The output of the program does not necessarily reflect its flow, since printing and accessing the queue are 2 separate operations (the operating system might decide to run the first command, and then stops the thread and runs another thread, before this thread performs the second command). • Surrounding the 2 commands with a synchronized block solves this problem, but it’s not advisable since it blocks too much. java.util.concurrent.Semaphore • A data structure used to restrict access to shared resources. • A synchronized block allows access for one thread at a time. • A semaphore gives N>=1 permits to threads, at the same time, over a resource/the code that comes after semaphore.acquire(<number>). • If the program uses acquire(), without a number, then the semaphore gives access to N threads. API: – http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Semaphore.h tml • Semaphore construction: – Semaphore sem = new Semaphore(int permits): • permits holds the maximal number of possible threads to access an object at the same time. • Fairness is false in this case, permits are given in an arbitrary order. – Semaphore sem = new Semaphore(int permits, boolean fair) • Fairness is true, gives permits to threads in FIFO manner. • First thread requesting access, is given access. • Downside: – It takes more time for the virtual machine to order the acquisition of the permits than to allow an arbitrary thread to acquire a permit. Some Semaphore Methods • sem.release(): releases a permit returning it to the semaphore. • sem.release(n): releases n permits - adds n permits to the semaphore (n can be larger than the value we used at initialization). • sem.reducePermits(n): shrinks the number of available permits by the indicated reduction; does not block like acquire(). (protected method) • sem.acquire(): acquire a permit • sem.acquire(n ): acquire n permits • More methods in the api: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ Semaphore.html Uses • • • • Limiting concurrent access to a resource, in general. Limiting the number of created threads. Limiting the number of concurrent connections. Etc. Code Example – In the Club • Groups of people asking for entrance permits to a club. Group1 Group2 requests n1 entrance permits requests n2 entrance permits requests n3 entrance permits Group3 requests n4 entrance permits Group4 requests n5 entrance permits Group5 FiftyCentTheBouncer Club 5 entrance permits Callable • java.util.concurrent.Callable : • Like Runnable, but: – Allows Threads to return values. – Allows Threads to throw exceptions. – Uses generics to define object types. – Class Header: public class <threadName> implements Callable<returnObjectName> – Required Functions: • public <returnObjectType> call() • Same purpose as Runnable’s run() Futures • Used in combination with the Executor. • An object that represents the result of a Callable. • Can retrieve the Callable’s result: – Using get() method – The result can be retrieved only when the computation has completed. – get() blocks, until value can be retrieved. • Allows cancellation of Thread execution. – Using cancel() method – Cannot cancel a completed Callable. • Interface: http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html Code Example – The Price is Right • A game were contestants try to guess the price of an item, given a max and a min value • . The contestant whose guess is closest to the actual price wins. makes a guess between $1 - $1000 Contestant1 makes a guess between $1 - $1000 Contestant2 Contestant3 makes a guess between $1 - $1000 makes a guess between $1 - $1000 Contestant4 makes a guess between $1 - $1000 Contestant5 ThePriceIsRight Item: Xerox Phaser 5500DN Workgroup Laser Printer. Actual price: $500 • Create n Callables and save their futures in a collection. • While not all n values were retrieved: – Acquire a semaphore (a semaphore is released at the end of each Callable) – Look for the Callable that finished, using the collection of futures. – Get the value returned by the callable that finished. – Set the found future to null in the collection, so it won’t be checked again. Notes • Runnable, Callable are objects, they are not threads. • Threads receive these objects and run them. • Threads receive a reference to these objects. Threads do not create a new copy of the runnable or the callable objects. • Having a stateful runnable/callable object (changes its own values) and running more than one thread to it will cause problems if not synchronized! • Runnable objects cannot throw exceptions back to main. Run() method does not throw Exception • Callable objects can throw exceptions back to main. Call() method throws Exception. Thread Cancellation • Thread t = new Thread(…); • How? – t.stop() method. (deprecated) • Good? (doesn’t leave the objects in a stable state) – Unsafe! – Releases all object locks instantly. • Then, how? – By implementing a “shouldStop” method. – “shouldStop” checks a flag in the thread. – Case where a flag is true, thread stops working. • Good? – Not always! – Thread might not take too long to stop: • In case where the thread in sleep condition. – Thread might not stop at all: • In case where the thread in wait() condition. And no notify() on the horizon. shouldStop Example class Worker implements Runnable { private boolean fShouldStop ; public Worker() { fShouldStop=false; } public synchronized void stop() { fShouldStop = true; } public synchronized boolean shouldStop() { return fShouldStop; } public void run() { while (!this.shouldStop()){ doTheWork(); } System.out.println("stopping…"); } } interrupt() • The interrupt() mechanism. • Each thread stores an internal flag known as interrupt status. • Methods: – t.isInterrupted() • Checks whether the thread is interrupted or not. – t.interrupt(): • If t is blocked (wait(), sleep()) then – InterruptedException is thrown. – Forces the thread to wake up! From sleep or wait mode. • Otherwise – isInterrupted() will return true. – Behaves the same as shouldStop. • Note: – If InterruptedException is thrown, isInterrupted() will return false unless interrupt() is called again. interrupt() example class Worker implements Runnable { public Worker() { } public boolean condition() { return false; } public synchronized void doSomeWork() { while (!this.condition() && !Thread.currentThread().isInterrupted()) { try { this.wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // re-raise the interrupt. This is very important! break; // get out of the loop (and out of the method) } } } public void run() { while (!Thread.currentThread().isInterrupted()){ doSomeWork(); } System.out.println("stopping ;)"); } } interrupt() example continued • class Driver{ public static void main(String[] args) { Thread t = new Thread(new Worker()); t.start(); try { Thread.sleep(100); } catch (InterruptedException e) { } t.interrupt(); } } Advanced Thread Synchronization Methods java.util.concurrent.CountDownLatch • What? – A synchronization method. – Allows one or more threads to wait until other threads complete. • How? – A CountDownLatch object is initialized with a starting value. – The await() method blocks until the current count reaches zero due to invocations of the countDown() method in other threads. – After which all waiting threads are released and any subsequent invocations of await return immediately. • Properties: – The CountDownLatch cannot be reset. – This is a good practice for initialization/finalization purposes. – When we need to use some waiting point only once, the latch is best to do the job. • Example: – In multiplayer games you don’t want any player to start until all players have joined. – This procedure works only once at the start of the game. • API: – http://docs.oracle.com/javase/1.5.0/docs/api/java/uti l/concurrent/CountDownLatch.html • Code Example: server waiting for clients to finish, before it shuts down. – CountDownLatch