Вы находитесь на странице: 1из 33

CONCURRENT PROGRAMMING

1)Multi-threaded programming Multitasking in your operating system: the ability to have more than one program working at what seems like the same time. For example, you can print while editing or downloading your email. Nowadays, you are likely to have a computer with more than one CPU, but the number of concurrently executing processes is not limited by the number of CPUs. The operating system assigns CPU time slices to each process, giving the impression of parallel activity. What is the difference between multiple processes and multiple threads? The essential difference is that while each process has a complete set of its own variables, threads share the same data. However, shared variables make communication between threads more efficient and easier to program than interprocess communication. Moreover, on some operating systems, threads are more lightweight than processesit takes less overhead to create and destroy individual threads than it does to launch new processes.

(For example, a browser should be able to simultaneously download multiple images. A web server needs to be able to serve concurrent requests. Graphical user interface (GUI) programs have a separate thread for gathering user interface events from the host operating environment.) (Multithreading changed dramatically in Java SE 5.0, with the addition of a large number of classes and interfaces that provide high-quality implementations of the mechanisms that most application programmers will need.)

Multithreading has several advantages over Multiprocessing such as; Threads are lightweight compared to processes Threads share the same address space and therefore can share both data and code Context switching between threads is usually less expensive than between processes Cost of thread intercommunication is relatively low that that of process intercommunication Threads allow different tasks to be performed concurrently.

Introduction to Threads
Multithreading refers to two or more tasks executing concurrently within a single program. A thread is an independent path of execution within a program. Many threads can run concurrently within a program. Every thread in Java is created and controlled by the java.lang.Thread class. A Java program can have many threads, and these threads can run concurrently, either asynchronously or synchronously.
Process: A process consists of the memory space allocated by the operating system that can contain one or more threads. A thread cannot exist on its own; it must be a part of a process. A process remains running until all of the non-daemon threads are done executing. Multithreading enables you to write very efficient programs that make maximum use of the CPU, because idle time can be kept to a minimum.

Life Cycle of a Thread: A thread goes through various stages in its life cycle. For example, a thread is born, started, runs, and then dies.

New: A new thread begins its life cycle in the new state. It remains in this state until the program starts the thread. It is also referred to as a born thread. Runnable: After a newly born thread is started, the thread becomes runnable. A thread in this state is considered to be executing its task. Waiting: Sometimes a thread transitions to the waiting state while the thread waits for another thread to perform a task.A thread transitions back to the runnable state only when another thread signals the waiting thread to continue executing. Timed waiting: A runnable thread can enter the timed waiting state for a specified interval of time. A thread in this state transitions back to the runnable state when that time interval expires or when the event it is waiting for occurs. Terminated: A runnable thread enters the terminated state when it completes its task or otherwise terminates.

Thread Priorities:

Every Java thread has a priority that helps the operating system determine the order in which threads are scheduled. Java priorities are in the range between MIN_PRIORITY (a constant of 1) and MAX_PRIORITY (a constant of 10). By default, every thread is given priority NORM_PRIORITY (a constant of 5). Threads with higher priority are more important to a program and should be allocated processor time before lower-priority threads. However, thread priorities cannot guarantee the order in which threads execute and very much platform dependentant.

Creating a Thread:
Java defines two ways in which this can be accomplished:

You can implement the Runnable interface. You can extend the Thread class, itself.

Creating a Thread Using Runnable interface.

The easiest way to create a thread is to create a class that implements the Runnable interface. To implement Runnable, a class need only implement a single method called run( ),
public void run( )

You will define the code that constitutes the new thread inside run() method.
3

It is important to understand that run() can call other methods, use other classes, and declare variables, just like the main thread can. After you create a class that implements Runnable, you will instantiate an object of type Thread from within that class. Thread constructors.
Thread(Runnable threadOb, String threadName);

Here threadOb is an instance of a class that implements the Runnable interface and the name of the new thread is specified by threadName. After the new thread is created, it will not start running until you call its start( ) method, which is declared within Thread.
void start( );

EXAMPLE
// Create a new thread. class NewThread implements Runnable { Thread t; NewThread() { // Create a new, second thread t = new Thread(this, "Demo Thread"); System.out.println("Child thread: " + t); t.start(); // Start the thread } // This is the entry point for the second thread. public void run() { try { for(int i = 5; i > 0; i--) { System.out.println("Child Thread: " + i); // Let the thread sleep for a while. Thread.sleep(500); } } catch (InterruptedException e) { System.out.println("Child interrupted."); } System.out.println("Exiting child thread."); } }

class ThreadDemo { public static void main(String args[]) { new NewThread(); // create a new thread try { for(int i = 5; i > 0; i--) { System.out.println("Main Thread: " + i); Thread.sleep(1000); } } catch (InterruptedException e) { System.out.println("Main thread interrupted."); } System.out.println("Main thread exiting."); } }

Child thread: Thread[Demo Thread,5,main] Main Thread: 5 Child Thread: 5 Child Thread: 4 Main Thread: 4 Child Thread: 3 Child Thread: 2 Main Thread: 3 Child Thread: 1 Exiting child thread. Main Thread: 2 Main Thread: 1 Main thread exiting.

Create Thread by Extending Thread:


The second way to create a thread is to create a new class that extends Thread, and then to create an instance of that class. The extending class must override the run( ) method, which is the entry point for the new thread. It must also call start( ) to begin execution of the new thread. 1. A class extending the Thread class overrides the run() method from the Thread class to define the code executed by the thread. 2. This subclass may call a Thread constructor explicitly in its constructors to initialize the thread, using the super() call. 3. The start() method inherited from the Thread class is invoked on the object of the class to make the thread eligible for running.
5

Thread Methods:
Following is the list of important medthods available in the Thread class. SN 1 Methods with Description public void start() Starts the thread in a separate path of execution, then invokes the run() method on this Thread object. public void run() If this Thread object was instantiated using a separate Runnable target, the run() method is invoked on that Runnable object. public final void setName(String name) Changes the name of the Thread object. There is also a getName() method for retrieving the name. public final void setPriority(int priority) Sets the priority of this Thread object. The possible values are between 1 and 10. public final void setDaemon(boolean on) A parameter of true denotes this Thread as a daemon thread. public final void join(long millisec) The current thread invokes this method on a second thread, causing the current thread to block until the second thread terminates or the specified number of milliseconds passes. public void interrupt() Interrupts this thread, causing it to continue execution if it was blocked for any reason. public final boolean isAlive() Returns true if the thread is alive, which is any time after the thread has been started but before it runs to completion.

4 5

Example: Here is the preceding program rewritten to extend Thread:


// Create a second thread by extending Thread class NewThread extends Thread { NewThread() { // Create a new, second thread super("Demo Thread"); System.out.println("Child thread: " + this); start(); // Start the thread } // This is the entry point for the second thread.

public void run() { try { for(int i = 5; i > 0; i--) { System.out.println("Child Thread: " + i); // Let the thread sleep for a while. Thread.sleep(500); } } catch (InterruptedException e) { System.out.println("Child interrupted."); } System.out.println("Exiting child thread."); } } class ExtendThread { public static void main(String args[]) { new NewThread(); // create a new thread try { for(int i = 5; i > 0; i--) { System.out.println("Main Thread: " + i); Thread.sleep(1000); } } catch (InterruptedException e) { System.out.println("Main thread interrupted."); } System.out.println("Main thread exiting."); } }

This would produce following result:


Child thread: Thread[Demo Thread,5,main] Main Thread: 5 Child Thread: 5 Child Thread: 4 Main Thread: 4 Child Thread: 3 Child Thread: 2 Main Thread: 3 Child Thread: 1 Exiting child thread. Main Thread: 2 Main Thread: 1 Main thread exiting.

Extra Example : Bouncing ball animation import import import import import import import java.awt.Container; java.awt.Dimension; java.awt.Graphics; java.awt.event.ActionEvent; java.awt.event.ActionListener; java.awt.event.WindowAdapter; java.awt.event.WindowEvent;

import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; public class BounceThread { public static void main(String[] args) { JFrame frame = new BounceThreadFrame(); frame.show(); } } class BounceThreadFrame extends JFrame { public BounceThreadFrame() { setSize(300, 200); setTitle("Bounce"); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); Container contentPane = getContentPane(); canvas = new JPanel(); contentPane.add(canvas, "Center"); JPanel p = new JPanel(); addButton(p, "Start", new ActionListener() { public void actionPerformed(ActionEvent evt) { Ball b = new Ball(canvas); b.start(); } });

addButton(p, "Close", new ActionListener() { public void actionPerformed(ActionEvent evt) { canvas.setVisible(false); System.exit(0); } }); contentPane.add(p, "South"); } public void addButton(Container c, String title, ActionListener a) { JButton b = new JButton(title); c.add(b); b.addActionListener(a); } private JPanel canvas; } class Ball extends Thread { public Ball(JPanel b) { box = b; } public void draw() { Graphics g = box.getGraphics(); g.fillOval(x, y, XSIZE, YSIZE); g.dispose(); } public void move() { if (!box.isVisible()) return; Graphics g = box.getGraphics(); g.setXORMode(box.getBackground()); g.fillOval(x, y, XSIZE, YSIZE); x += dx; y += dy; Dimension d = box.getSize(); if (x < 0) { x = 0; dx = -dx; }

if (x + XSIZE >= d.width) { x = d.width - XSIZE; dx = -dx; } if (y < 0) { y = 0; dy = -dy; } if (y + YSIZE >= d.height) { y = d.height - YSIZE; dy = -dy; } g.fillOval(x, y, XSIZE, YSIZE); g.dispose(); } public void run() { try { draw(); for (int i = 1; i <= 1000; i++) { move(); sleep(5); } } catch (InterruptedException e) { } } private JPanel box; private static final int XSIZE = 10; private static final int YSIZE = 10; private int x = 0; private int y = 0; private int dx = 2; private int dy = 2; }

10

2)Interrupting Threads A thread terminates when its run method returns, by executing a return statement, after executing the last statement in the method body, or if an exception occurs that is not caught in the method. There is a way to force a thread to terminate. However, the interrupt method can be used to request termination of a thread. When the interrupt method is called on a thread, the interrupted status of the thread is set. This is a boolean flag that is present in every thread. Each thread should occasionally check whether it has been interrupted. To find out whether the interrupted status was set, first call the static Thread.currentThread method to get the current thread and then call the isInterrupted method: while (!Thread.currentThread().isInterrupted() && more work to do) { do more work } if a thread is blocked, it cannot check the interrupted status. When the interrupt method is called on a thread that blocks on a call such as sleep or wait, the blocking call is terminated by an InterruptedException. Interrupting a thread simply grabs its attention. The interrupted thread can decide how to react to the interruption. Some threads are so important that they should handle the exception and continue. public void run() { try { ... while (!Thread.currentThread().isInterrupted() && more work to do) { do more work } } catch(InterruptedException e) { // thread was interrupted during sleep or wait } finally { cleanup, if required } // exiting the run method terminates the thread }

11

The isInterrupted check is neither necessary nor useful if you call the sleep method (or another interruptible method) after every work iteration. If you call the sleep method when the interrupted status is set, it doesnt sleep. Instead, it clears the status (!) and throws an InterruptedException. public void run() { try { ... while (more work to do) { do more work Thread.sleep(delay); } } catch(InterruptedException e) { // thread was interrupted during sleep } finally { cleanup, if required } // exiting the run method terminates the thread }

void interrupt() sends an interrupt request to a thread. The interrupted status of the thread is set to true. If the thread is currently blocked by a call to sleep, then an InterruptedException is thrown. static boolean interrupted() tests whether the current thread (that is, the thread that is executing this instruction) has been interrupted. Note that this is a static method. The call has a side effectit resets the interrupted status of the current thread to false. boolean isInterrupted() tests whether a thread has been interrupted. Unlike the static interrupted method, this call does not change the interrupted status of the thread. static Thread currentThread() returns the Thread object representing the currently executing thread.

12

public class SleepInterrupt extends Object implements Runnable { public void run() { try { System.out.println("in run() - sleep for 20 seconds"); Thread.sleep(20000); System.out.println("in run() - woke up"); } catch (InterruptedException x) { System.out.println("in run() - interrupted while sleeping"); return; } System.out.println("in run() - leaving normally"); } public static void main(String[] args) { SleepInterrupt si = new SleepInterrupt(); Thread t = new Thread(si); t.start(); // Be sure that the new thread gets a chance to // run for a while. try { Thread.sleep(2000); } catch (InterruptedException x) { } System.out.println("in main() - interrupting other thread"); t.interrupt(); System.out.println("in main() - leaving"); } }

13

3)Thread States Threads can be in one of six states: New Runnable Blocked Waiting Timed waiting Terminated

New Threads When you create a thread with the new operator for example, new Thread(r)the thread is not yet running. This means that it is in the new state. When a thread is in the new state, the program has not started executing code inside of it.

Runnable Threads Once you invoke the start method, the thread is in the runnable state. A runnable thread may or may not actually be running. It is up to the operating system to give the thread time to run. Once a thread is running, it doesnt necessarily keep running. In fact, it is desirable if running threads occasionally pause so that other threads have a chance to run. Preemptive scheduling systems give each runnable thread a slice of time to perform its task. When that slice of time is exhausted, the operating system preempts the thread and gives another thread an opportunity to work.

Blocked and Waiting Threads When a thread is blocked or waiting, it is temporarily inactive. It doesnt execute any code and it consumes minimal resources. When the thread tries to acquire an intrinsic object lock, that is currently held by another thread, it becomes blocked. The thread becomes unblocked when all other threads have relinquished the lock and the thread scheduler has allowed this thread to hold it. When the thread waits for another thread to notify the scheduler of a condition, it enters the waiting state. Several methods have a timeout parameter. Calling them causes the thread to enter the timed waiting state.

14

Terminated Threads A thread is terminated for one of two reasons: It dies a natural death because the run method exits normally. It dies abruptly because an uncaught exception terminates the run method. In particular, you can kill a thread by invoking its stop method. That method throws a ThreadDeath error object that kills the thread. However, the stop method is deprecated, and you should never call it in your own code.

15

4)Thread Properties
The Propeeties of Thread are 1. 2. 3. 4. thread priorities daemon threads thread groups handlers for uncaught exceptions.

Thread Priorities In the Java programming language, every thread has a priority. By default, a thread inherits the priority of the thread that constructed it. You can increase or decrease the priority of any thread with the setPriority method. You can set the priority to any value between MIN_PRIORITY (defined as 1 in the Thread class) and MAX_PRIORITY (defined as 10). NORM_PRIORITY is defined as 5. Whenever the thread-scheduler has a chance to pick a new thread, it prefers threads with higher priority. However, thread priorities are highly system dependent.

Daemon Threads A thread can be turned into a daemon thread by calling t.setDaemon(true); There is nothing demonic about such a thread. A daemon is simply a thread that has no other role in life than to serve others. Examples are timer threads that send regular "timer ticks" to other threads. When only daemon threads remain, then the program exits. There is no point in keeping the program running if all remaining threads are daemons.

Thread Groups Some programs contain quite a few threads. It then becomes useful to categorize them by functionality. For example, consider an Internet browser. If many threads are trying to acquire images from a server and the user clicks on a "Stop" button to interrupt the loading of the current page, then it is handy to have a way of interrupting all of these threads simultaneously. The Java programming language lets you construct what it calls a thread group so you can simultaneously work with a group of threads.

16

You construct a thread group with the constructor: String groupName = . . .; ThreadGroup g = new ThreadGroup(groupName) The string argument of the ThreadGroup constructor identifies the group and must be unique. Y ou then add threads to the thread group by specifying the thread group in the thread constructor. Thread t = new Thread(g, threadName);

To find out whether any threads of a particular group are still runnable, use the activeCount method. if (g.activeCount() == 0) { // all threads in the group g have stopped } To interrupt all threads in a thread group, simply call interrupt on the group object. g.interrupt(); // interrupt all threads in group g Thread groups can have child subgroups. By default, a newly created thread group becomes a child of the current thread group. But you can also explicitly name the parent group in the constructor (see the API notes). Methods such as activeCount and interrupt refer to all threads in their group and all child groups.

Handlers for Uncaught Exceptions The run method of a thread cannot throw any checked exceptions, but it can be terminated by an unchecked exception. In that case, the thread dies. However, there is no catch clause to which the exception can be propagated. Instead, just before the thread dies, the exception is passed to a handler for uncaught exceptions. The handler must belong to a class that implements the Thread.UncaughtExceptionHandler interface. That interface has a single method, void uncaughtException(Thread t, Throwable e)

17

5)Synchronization

The Java programming language provides two basic synchronization idioms: synchronized methods synchronized statements

synchronized methods: To make a method synchronized, simply add the synchronized keyword to its declaration: public class SynchronizedCounter { private int c = 0; public synchronized void increment() { c++; } public synchronized void decrement() { c--; } public synchronized int value() { return c; } } First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.

Second, when a synchronized method exits, it automatically establishes a happensbefore relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.

Synchronized methods enable a simple strategy for preventing thread interference and memory consistency errors: if an object is visible to more than one thread, all reads or writes to that object's variables are done through synchronized methods.

18

Intrinsic Locks and Synchronization Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships that are essential to visibility.

Every object has an intrinsic lock associated with it. A thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them. A thread is said to own the intrinsic lock between the time it has acquired the lock and released the lock. As long as a thread owns an intrinsic lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock. When a thread releases an intrinsic lock, a happens-before relationship is established between that action and any subsequent acquistion of the same lock. Locks In Synchronized Methods

When a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method's object and releases it when the method returns. The lock release occurs even if the return was caused by an uncaught exception. You might wonder what happens when a static synchronized method is invoked, since a static method is associated with a class, not an object. In this case, the thread acquires the intrinsic lock for the Class object associated with the class. Thus access to class's static fields is controlled by a lock that's distinct from the lock for any instance of the class. Synchronized Statements

Another way to create synchronized code is with synchronized statements. public void addName(String name) { synchronized(this) { lastName = name; nameCount++; } nameList.add(name); }

19

Synchronized statements are also useful for improving concurrency with fine-grained synchronization. public class MsLunch { private long c1 = 0; private long c2 = 0; private Object lock1 = new Object(); private Object lock2 = new Object(); public void inc1() { synchronized(lock1) { c1++; } } public void inc2() { synchronized(lock2) { c2++; } } } Reentrant Synchronization

Recall that a thread cannot acquire a lock owned by another thread. But a thread can acquire a lock that it already owns. Allowing a thread to acquire the same lock more than once enables reentrant synchronization. This describes a situation where synchronized code, directly or indirectly, invokes a method that also contains synchronized code, and both sets of code use the same lock.

20

Deadlock
Deadlock describes a situation where two or more threads are blocked forever, waiting for each other. When two threads or processes are waiting for each other to release the resource or object they holds and so are blocked forever. This situation is called deadlock. For example if one thread is holding the lock on some object that the other thread is waiting for and the other thread is holding lock on some object the first one is waiting for then they both will wait for each other to release the object they need to finish their operation but no one will release the hold object and so they will wait for each other forever.

public class Deadlock { static class Friend { private final String name; public Friend(String name) { this.name = name; } public String getName() { return this.name; } public synchronized void bow(Friend bower) { System.out.format("%s: %s has bowed to me!%n", this.name, bower.getName()); bower.bowBack(this); } public synchronized void bowBack(Friend bower) { System.out.format("%s: %s has bowed back to me!%n", this.name, bower.getName()); } } public static void main(String[] args) { final Friend alphonse = new Friend("Alphonse"); final Friend gaston = new Friend("Gaston"); new Thread(new Runnable(){ public void run() { alphonse.bow(gaston); } new Thread(new Runnable() { public void run() { gaston.bow(alphonse); } } } }).start(); }).start();

21

6)Thread-Safe Collections If multiple threads concurrently modify a data structure such as a hash table, then it is easily possible to damage the data structure. For example, one thread may begin to insert a new element. Suppose it is preempted while it is in the middle of rerouting the links between the hash tables buckets. If another thread starts traversing the same list, it may follow invalid links and create havoc, perhaps throwing exceptions or being trapped in an infinite loop. You can protect a shared data structure by supplying a lock, but it is usually easier to choose a thread-safe implementation instead.

Efficient Maps, Sets, and Queues The java.util.concurrent package supplies efficient implementations for maps, sorted sets, and queues: 1. 2. 3. 4. ConcurrentHashMap ConcurrentSkipListMap ConcurrentSkipListSet ConcurrentLinkedQueue

These collections use sophisticated algorithms that minimize contention by allowing concurrent access to different parts of the data structure. The concurrent hash map can efficiently support a large number of readers and a fixed number of writers. By default, it is assumed that there are up to 16 simultaneous writer threads. There can be many more writer threads, but if more than 16 write at the same time, the others are temporarily blocked. You can specify a higher number in the constructor, but it is unlikely that you will need to. The ConcurrentHashMap and ConcurrentSkipListMap classes have useful methods for atomic insertion and removal of associations. The putIfAbsent method atomically adds a new association provided there wasnt one before.

This is useful for a cache that is accessed by multiple threads, to ensure that only one thread adds an item into the cache: cache.putIfAbsent(key, value);

The opposite operation removeIfPresent). The call

is

remove

(which

perhaps

should

have

been

called

cache.remove(key, value)

22

atomically removes the key and value if they are present in the map. Finally, cache.replace(key, oldValue, newValue) atomically replaces the old value with the new one, provided the old value was associated with the given key. Copy on Write Arrays The CopyOnWriteArrayList and CopyOnWriteArraySet are thread-safe collections in which all mutators make a copy of the underlying array. This arrangement is useful if the number of threads that iterate over the collection greatly outnumbers the threads that mutate it.

7)Executors
Constructing a new thread is somewhat expensive because it involves interaction with the operating system. If your program creates a large number of short-lived threads, then it should instead use a thread pool. A thread pool contains a number of idle threads that are ready to run. You give a Runnable to the pool, and one of the threads calls the run method. When the run method exits, the thread doesnt die but stays around to serve the next request. Another reason to use a thread pool is to throttle the number of concurrent threads. Creating a huge number of threads can greatly degrade performance and even crash the virtual machine. If you have an algorithm that creates lots of threads, then you should use a fixed thread pool that bounds the total number of concurrent threads. The Executors class has a number of static factory methods for constructing thread pools.

23

Thread Pools The newCachedThreadPool method constructs a thread pool that executes each task immediately, using an existing idle thread when available and creating a new thread otherwise. The newFixedThreadPool method constructs a thread pool with a fixed size. If more tasks are submitted than there are idle threads, then the unserved tasks are placed on a queue. They are run when other tasks have completed. The newSingleThreadExecutor is a degenerate pool of size 1: A single thread executes the submitted tasks, one after another. These three methods return an object of the ThreadPoolExecutor class that implements the ExecutorService interface.

Scheduled Execution The ScheduledExecutorService interface has methods for scheduled or repeated execution of tasks. It is a generalization of java.util.Timer that allows for thread pooling. The newScheduledThreadPool and newSingleThreadScheduledExecutor methods of the Executors class return objects that implement the ScheduledExecutorService interface. You can schedule a Runnable or Callable to run once, after an initial delay. You can also schedule a Runnable to run periodically.

You can submit a Runnable or Callable to an ExecutorService with one of the following methods: Future<?> submit(Runnable task) Future<T> submit(Runnable task, T result) Future<T> submit(Callable<T> task) The pool will run the submitted task at its earliest convenience. When you call submit, you get back a Future object that you can use to query the state of the task. The first submit method returns an odd-looking Future<?>. You can use such an object to call isDone, cancel, or isCancelled. But the get method simply returns null upon completion. The second version of submit also submits a Runnable, and the get method of the Future returns the given result object upon completion. The third version submits a Callable, and the returned Future gets the result of the computation when it is ready.When you are done with a thread pool, call shutdown.

This method initiates the shutdown sequence for the pool. An executor that is shut down accepts no new tasks. When all tasks are finished, the threads in the pool die. Alternatively, you can call shutdownNow.

24

The pool then cancels all tasks that have not yet begun and attempts to interrupt the running threads. Here, in summary, is what you do to use a connection pool: 1) Call the static newCachedThreadPool or newFixedThreadPool method of the Executors class. 2) Call submit to submit Runnable or Callable objects. 3) If you want to be able to cancel a task or if you submit Callable objects, hang on to the returned Future objects. 4) Call shutdown when you no longer want to submit any tasks.

8)Synchronizers
Blocking queues are unique among the collections classes: not only do they act as containers for objects, but they can also coordinate the control flow of producer and consumer threads because take and put block until the queue enters the desired state (not empty or not full). A synchronizer is any object that coordinates the control flow of threads based on its state. Blocking queues can act as synchronizers; other types of synchronizers include semaphores, barriers, and latches. All synchronizers share certain structural properties: they encapsulate state that determines whether threads arriving at the synchronizer should be allowed to pass or forced to wait, provide methods to manipulate that state, and provide methods to wait efficiently for the synchronizer to enter the desired state.

25

Semaphores
Semaphores are used to control the number of activities that can access a certain resource or perform a given action at the same time. Counting semaphores can be used to implement resource pools or to impose a bound on a collection. A Semaphore manages a set of virtual permits; the initial number of permits is passed to the Semaphore constructor. Activities can acquire permits (as long as some remain) and release permits when they are done with them. If no permit is available, acquire blocks until one is (or until interrupted or the operation times out). The release method returns a permit to the semaphore.

A degenerate case of a counting semaphore is a binary semaphore, a Semaphore with an initial count of one. A binary semaphore can be used as a mutex with nonreentrant locking semantics; whoever holds the sole permit holds the mutex.

Semaphores are useful for implementing resource pools such as database connection pools. While it is easy to construct a fixed-sized pool that fails if you request a resource from an empty pool, what you really want is to block if the pool is empty and unblock when it becomes nonempty again. If you initialize a Semaphore to the pool size, acquire a permit before trying to fetch a resource from the pool, and release the permit after putting a resource back in the pool, acquire blocks until the pool becomes nonempty.

Latches A latch is a synchronizer that can delay the progress of threads until it reaches its terminal state. A latch acts as a gate: until the latch reaches the terminal state the gate is closed and no thread can pass, and in the terminal state the gate opens, allowing all threads to pass. Once the latch reaches the terminal state, it cannot change state again, so it remains open forever.

26

Latches can be used to ensure that certain activities:] Ensuring that a computation does not proceed until resources it needs have been initialized. Ensuring that a service does not start until other services on which it depends have started. Waiting until all the parties involved in an activity, for instance the players in a multi-player game, are ready to proceed. In this case, the latch reaches the terminal state after all the players are ready.
Countdown Latches A CountDownLatch lets a set of threads wait until a count has reached zero. The countdown latch is one-time only. Once the count has reached 0, you cannot increment it again. A useful special case is a latch with a count of 1. This implements a one-time gate. Threads are held at the gate until another thread sets the count to 0.

Imagine, for example, a set of threads that need some initial data to do their work. The worker threads are started and wait at the gate. Another thread prepares the data. When it is ready, it calls countDown, and all worker threads proceed. You can then use a second latch to check when all worker threads are done. Initialize the latch with the number of threads. Each worker thread counts down that latch just before it terminates. Another thread that harvests the work results waits on the latch, and it proceeds as soon as all workers have terminated. Barriers Barriers are similar to latches in that they block a group of threads until some event has occurred. The key difference is that with a barrier, all the threads must come together at a barrier point at the same time in order to proceed. Latches are for waiting for events; barriers are for waiting for other threads. The CyclicBarrier class implements a rendezvous called a barrier. Consider a number of threads that are working on parts of a computation. When all parts are ready, the results need to be combined. When a thread is done with its part, we let it run against the barrier. Once all threads have reached the barrier, the barrier gives way and the threads can proceed.

Here are the details. First, construct a barrier, giving the number of participating threads: CyclicBarrier barrier = new CyclicBarrier(nthreads); Each thread does some work and calls await on the barrier upon completion: public void run() { doWork(); barrier.await(); ... } The await method takes an optional timeout parameter: barrier.await(100, TimeUnit.MILLISECONDS);

27

If any of the threads waiting for the barrier leaves the barrier, then the barrier breaks. (A thread can leave because it called await with a timeout or because it was interrupted.) In that case, the await method for all other threads throws a BrokenBarrierException. Threads that are already waiting have their await call terminated immediately. You can supply an optional barrier action that is executed when all threads have reached the barrier: Runnable barrierAction = . . .; CyclicBarrier barrier = new CyclicBarrier(nthreads, barrierAction); The action can harvest the result of the individual threads. The barrier is called cyclic because it can be reused after all waiting threads have been released. In this regard, it differs from a CountDownLatch, which can only be used once. Exchangers An Exchanger is used when two threads are working on two instances of the same data buffer. Typically, one thread fills the buffer, and the other consumes its contents. When both are done, they exchange their buffers.

9)Threads and event-driven programming


Swing is not thread safe. If you try to manipulate user interface elements from multiple threads, then your user interface can become corrupted. The Swing API was designed to be powerful, flexible, and easy to use. In particular, we wanted to make it easy for programmers to build new Swing components, whether from scratch or by extending components that we provide. For this reason, we do not require Swing components to support access from multiple threads. Instead, we make it easy to send requests to a component so that the requests run on a single thread.

Once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread.

This rule might sound scary, but for many simple programs, you don't have to worry about threads. Before we go into detail about how to write Swing code, let's define two terms: realized and event-dispatching thread.

28

Realized means that the component's paint() method has been or might be called. A Swing component that's a top-level window is realized by having one of these methods invoked on it: setVisible(true), show(), or (this might surprise you) pack(). Once a window is realized, all components that it contains are realized. Another way to realize a component is to add it to a container that's already realized. You'll see examples of realizing components later. The event-dispatching thread is the thread that executes drawing and event-handling code. For example, the paint() and actionPerformed() methods are automatically executed in the event-dispatching thread. Another way to execute code in the event-dispatching thread is to use the SwingUtilities invokeLater() method.

There are a few exceptions to the rule that all code that might affect a realized Swing component must run in the event-dispatching thread: 1) A few methods are thread-safe: In the Swing API documentation, thread-safe methods are marked with this text: This method is thread safe, although most Swing methods are not. 2)An application's GUI can often be constructed and shown in the main thread: The following typical code is safe, as long as no components (Swing or otherwise) have been realized:
public class MyApplication { public static void main(String[] args) { JFrame f = new JFrame("Labels"); // Add components to // the frame here... f.pack(); f.show(); // Don't do any more GUI work here... } } All the code shown above runs on the "main" thread. The f.pack() call realizes the components under the JFrame. This means that, technically, the f.show() call is unsafe and should be executed in the event-dispatching thread. However, as long as the program doesn't already have a visible GUI, it's exceedingly unlikely that the JFrame or its contents will receive a paint() call before f.show() returns. Because there's no GUI code after the f.show() call, all GUI work moves from the main thread to the event-dispatching thread, and the preceding code is, in practice, thread-safe.

29

3)An applet's GUI can be constructed and shown in the init() method: Existing browsers don't draw an applet until after its init() and start() methods have been called. Thus, constructing the GUI in the applet's init() method is safe, as long as you never call show() or setVisible(true) on the actual applet object. By the way, applets that use Swing components must be implemented as subclasses of JApplet, and components should be added to the JApplet content pane, rather than directly to the JApplet. As for any applet, you should never perform time-consuming initialization in the init() or start() method; instead, you should start a thread that performs the timeconsuming task.

4)The following JComponent methods are safe to call from any thread: repaint(), revalidate(), and invalidate(). The repaint() and revalidate() methods queue requests for the event-dispatching thread to call paint() and validate(), respectively. The invalidate() method just marks a component and all of its direct ancestors as requiring validation.

5)Listener lists can be modified from any thread: It's always safe to call the addListenerTypeListener() and removeListenerTypeListener() methods. The add/remove operations have no effect on an event dispatch that's under way.

Most post-initialization GUI work naturally occurs in the event-dispatching thread. Once the GUI is visible, most programs are driven by events such as button actions or mouse clicks, which are always handled in the event-dispatching thread. However, some programs need to perform non-event-driven GUI work after the GUI is visible. Here are some examples: Programs that must perform a lengthy initialization operation before they can be used: This kind of program should generally show some GUI while the initialization is occurring, and then update or change the GUI. The initialization should not occur in the event-dispatching thread; otherwise, repainting and event dispatch would stop. However, after initialization the GUI update/change should occur in the event-dispatching thread, for thread-safety reasons. Programs whose GUI must be updated as the result of non-AWT events: For example, suppose a server program can get requests from other programs that might be running on different machines. These requests can come at any time, and they result in one of the server's methods being invoked in some possibly unknown thread. How can that method update the GUI? By executing the GUI update code in the event-dispatching thread.

30

The SwingUtilities class provides two methods to help you run code in the event-dispatching thread: invokeLater(): Requests that some code be executed in the event-dispatching thread. This method returns immediately, without waiting for the code to execute. invokeAndWait(): Acts like invokeLater(), except that this method waits for the code to execute. As a rule, you should use invokeLater() instead of this method.

Example
import java.awt.Graphics; import java.util.Random; import java.awt.Color; import java.awt.Dimension; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JOptionPane; class bounceball extends JPanel { private static final int win_w=640; private static final int win_h=480; private float rad=100;// radius of the ball private float x=rad+50; private float y=rad+20;//center coordinates of the ball private float sx=4; private float sy=3; //change in the coordinates(x and y) private static final int update_rate=30;//refresh of screen per second // Now constructor private Random r; private Color clr=Color.BLUE; public void set(Color c) { clr=c; } public Color get() { return clr; } public bounceball() { r=new Random(); setPreferredSize(new Dimension(win_w,win_h)); //size of the panel is set to the size of the window

31

Thread ballthread=new Thread() { public void run() { while(true) { x+=sx; y+=sy; //here we handle collision with the window walls //checking the horizontal collision if(x-rad<0) { sx=-sx;//reverse the direction x=rad; //set(new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256))); } else if(x+rad>win_w) { sx=-sx; x=win_w-rad; //set(new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256))); } //checking the vertical collision if(y-rad<0) { sy=-sy; y=rad; //set(new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256))); } else if(y+rad>win_h) { sy=-sy; y=win_h-rad; //set(new Color(r.nextInt(256),r.nextInt(256),r.nextInt(256))); } repaint(); try { Thread.sleep(1000/update_rate); } catch(InterruptedException e) { JOptionPane.showMessageDialog(null,"Please don't interrupt me while sleeping !","Disturbed",JOptionPane.ERROR_MESSAGE); }

32

} } }; ballthread.start();//start the thread's execution } public void paintComponent(Graphics g) { super.paintComponent(g); g.setColor(Color.WHITE); g.fillRect(0,0,win_w,win_h); g.setColor(get()); g.fillOval((int)(x-rad),(int)(y-rad),(int)(2*rad),(int)(2*rad)); g.setColor(Color.WHITE); String s=String.format("Position:[%3.0f,%3.0f]",x,y); g.drawString(s,20,40); } public static void main(String [] args) { JFrame jr=new JFrame("Bouncing ball."); bounceball ball=new bounceball(); jr.add(ball); jr.setVisible(true); jr.setSize(650,500); jr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jr.pack(); } }

33

Вам также может понравиться