Download Blocking Queues

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Blocking Queues An alternative to hand coding with notify and wait. PRODUCER package blockingqueue;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
class Producer implements Runnable {
private static Random randGen = new Random();
private final BlockingQueue queue;
Producer(BlockingQueue q) { queue = q; }
public void run() {
try {
while(true) { queue.put(produce()); }
} catch (InterruptedException ex) { ;}
}
Object produce() throws InterruptedException
Thread.sleep(randGen.nextInt(800));
return new Date(); }
}
{
CONSUMER package blockingqueue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
class Consumer implements Runnable {
private final BlockingQueue queue;
private static int idnum = 1;
private int myid;
Consumer(BlockingQueue q) {
queue = q;
myid = idnum++;
}
public void run() {
try {
while(true) { consume(queue.take()); }
} catch (InterruptedException ex) {;}
}
void consume(Object x) {
System.out.println("ID=" + myid + ": "
}
+ x);
public static void main(String [] args) {
BlockingQueue q = new ArrayBlockingQueue(10);
Producer p = new Producer(q);
Consumer c1 = new Consumer(q);
Consumer c2 = new Consumer(q);
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
}
Executor LifeCycle example ­ from Goetz, p 122 package net.jcip.examples;
import
import
import
import
import
java.io.IOException;
java.net.ServerSocket;
java.net.Socket;
java.util.concurrent.*;
java.util.logging.*;
/**
* LifecycleWebServer
* <p/>
* Web server with shutdown support
*
* @author Brian Goetz and Tim Peierls
*/
public class LifecycleWebServer {
private final ExecutorService exec =
Executors.newCachedThreadPool();
public void start() throws IOException {
ServerSocket socket = new ServerSocket(80);
while (!exec.isShutdown()) {
try {
final Socket conn = socket.accept();
exec.execute(new Runnable() {
public void run() {
handleRequest(conn);
}
});
} catch (RejectedExecutionException e) {
if (!exec.isShutdown())
log("task submission rejected", e);
}
}
}
public void stop() {
exec.shutdown();
}
private void log(String msg, Exception e) {
Logger.getAnonymousLogger().log(Level.WARNING, msg, e);
}
void handleRequest(Socket connection) {
Request req = readRequest(connection);
if (isShutdownRequest(req))
stop();
else
dispatchRequest(req);
}
interface Request {
}
private Request readRequest(Socket s) {
return null;
}
private void dispatchRequest(Request r) {
}
private boolean isShutdownRequest(Request r) {
return false;
}
}
Callable and Futures Till Java 1.4, threads could be implemented by either implementing Runnable or extending Thread. This
was quite simple, but had a serious limitation - They have a run method that cannot return values. In
order to side-step this, most programmers use side-effects (writing to a file etc.) to mimic returning values
to the invoker of the thread. Java 5 introduces the Callable interface, that allows users to return values
from a thread. This post describes the Callable and Future interfaces and shows an example of how to
use these to interfaces.
Jump to Sample Code
public interface Callable<V> {
V call() throws Exception;
}
The call() method is the entry point into a Callable object, and it's return type is the type parameter set in
the Callable object. To implement Callable with no return value, use Callable<void>. Also, note that
the call() method throws a checked exception, as compared to the run() method in Runnable which
does not throw any exception. The Executors class contains utility methods to convert from other
common forms to Callable classes. However, Callable cannot be used in place of a Runnable. Callable
objects have to be invoked by ExecutorService. The Executor framework provides the Future interface to
allow handling the cancellation and returns of a Callable object.
A Future represents the result of an asynchronous computation.
public interface Future {
//Attempts to cancel execution of this task.
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
// Waits if necessary for the computation to complete,
// and then retrieves its result.
V get() throws InterruptedException, ExecutionException;
// Waits if necessary for at most the given time for the computation
// to complete, and then retrieves its result, if available.
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
The result can be retrieved using method get() when the computation has completed, blocking if
necessary until it is ready. If you would like to use a Future for the sake of cancellation but not provide
a usable result, you can declare types of the form Future<?> and return null as a result of the underlying
task. The following example demonstrates the use of Callable and future. The first CallableImpl class
implements the Callable interface, and returns an integer that is sent to it's constructor. The
CallableTester class invokes the CallableImpl through an executor.
public class CallableImpl implements Callable<Integer> {
private int myName;
CallableImpl(int i){
myName = i;
}
public Integer call() {
for(int i = 0; i < 10; i++) {
System.out.println("Thread : " + getMyName() + " I is : " + i);
}
return new Integer(getMyName());
}
public int getMyName() {
return myName;
}
public void setMyName(int myName) {
this.myName = myName;
}
}
CallableImpl.java
public class CallableTester {
public static void main(String[] args) {
Callable<Integer> callable = new CallableImpl(2);
ExecutorService executor = new ScheduledThreadPoolExecutor(5);
Future<Integer> future = executor.submit(callable);
try {
System.out.println("Future value: " + future.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}
CallableTester.java
ExecutorService extends Executor to provides method to manage thread termination and methods that
can produce a Future for tracking progress of one or more asynchronous tasks. The method submit
extends Executor.execute(java.lang.Runnable) to create and return a Future. Methods invokeAny and
invokeAll perform the most commonly useful forms of bulk execution, executing a collection of tasks and
then waiting for at least one, or all, to complete.
Using Callable to Return Results From Runnables
by John Zukowski
The Runnable interface has been around since the beginning of time for the Java
platform. It allows you to define a task to be completed by a thread. As most people
probably know already, it offers a single method run() that accepts no arguments and
returns no values, nor can it throw any checked exceptions. If you need to get a value
back from the now-completed task, you must use a method outside the interface and
wait for some kind of notification message that the task completed. For example, the
following demonstrates what you might do for just such a scenario:
Runnable runnable = ...;
Thread t = new Thread(runnable);
t.start();
t.join();
String value = someMethodtoGetSavedValue()
Nothing is inherently wrong with this code, but it can be done differently now, thanks to
the Callable interface introduced in J2SE 5.0. Instead of having a run() method,
the Callable interface offers a call() method, which can return an Object or, more
specifically, any type that is introduced in the genericized form:
public interface Callable<V> {
V call() throws Exception;
}
Because you cannot pass a Callable into a Thread to execute, you instead use
the ExecutorService to execute theCallable object. The service
accepts Callable objects to run by way of the submit() method:
<T> Future<T> submit(Callable<T> task)
As the method definition shows, submitting a Callable object to
the ExecutorService returns a Future object. The get()method of Future will then block
until the task is completed. This is the equivalent of the join() call in the first example.
Actually, it is the equivalent of both the join() call and the get value call
as get() returns the value calculated by theCallable instance.
To demonstrate, the following example creates separate Callable instances for each
word passed in on the command line and sums up their length. Each Callable will just
calculate the sum of its individual word. The set of Future objects are saved to acquire
the calculated value from each. If the order of the returned values needed to be
preserved, aList could be used instead.
import java.util.*;
import java.util.concurrent.*;
public class CallableExample {
public static class WordLengthCallable
implements Callable {
private String word;
public WordLengthCallable(String word) {
this.word = word;
}
public Integer call() {
return Integer.valueOf(word.length());
}
}
public static void main(String args[]) throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(3);
Set<Future<Integer>> set = new HashSet<Future&lg;Integer>>();
for (String word: args) {
Callable<Integer> callable = new WordLengthCallable(word);
Future<Integer> future = pool.submit(callable);
set.add(future);
}
int sum = 0;
for (Future<Integer> future : set) {
sum += future.get();
}
System.out.printf("The sum of lengths is %s%n", sum);
System.exit(sum);
}
}
The WordLengthCallable saves each word and uses the word's length as the value
returned by the call() method. This value could take some time to generate but in this
case is known immediately. The only requirement of call() is the value is returned at
the end of the call. When the get() method of Future is later called, the Future will
either have the value immediately if the task runs quickly, as in this case, or will wait
until the value is done generating. Multiple calls to get() will not cause the task to be
rerun in the thread.
Because the goal of the program is to calculate the sum of all word lengths, it doesn't
matter in which order the Callable tasks finish. It is perfectly OK if the last task
completes before the first three. The first get() call to Future will just wait for the first
task in the Set to complete. This does not block other tasks from running to completion
separately. It is just waiting for that one thread or task to complete.
This particular example uses a fixed-size thread pool for the ExecutorService, but any
available service will do.
For more information on the use of executors and thread pools, see the Executors
lesson in the Java Tutorial. The SwingWorker class is another example of
a Runnable object that works with a Future, though in a slightly different way. See
the Worker Threads and SwingWorker lesson for more information on that.