You are on page 1of 15

Concurrencia de alto nivel en Java

Aqu veremos algunas construcciones de alto nivel de Java para


manejar la concurrencia.
En primer lugar veremos cmo lanzar threads en el propio
constructor de una clase.
A continuacin veremos diferentes clases que resuelven de forma
sencilla problemas que con otras primitivas (semforos, monitores,
etc) sera ms tedioso solucionar.

Lanzando threads en el constructor


class AutoThread implements Runnable {
private Thread me_;
public AutoThread() {
me_ = new Thread(this);
me_.start();
}
public void run() {
if (me_==Thread.currentThread())
for (int i=0;i<10;i++)
System.out.println (En Autothread.run()");
}
public static void main(String[] args) {
AutoThread miThread = new AutoThread();
for (int i = 0;i<10;i++)
System.out.println ("Dentro de main()");
}
}

public static void main (String[] args) {


AutoThread t = new AutoThread();
t.run();
for (int i = 0;i<10;i++)
System.out.println (Dentro del main());
}
}

Algunas clases interesantes en java.util.concurrent


LinkedBlockingQueue
ConcurrentLinkedQueue
ConcurrentLinkedDeque
ConcurrentHashMap
SynchronousQueue
Exchanger
CountDownLatch
CyclicBarrier

LinkedBlockingQueue <E>
import java.util.concurrent.*;
public class Productor implements Runnable {
LinkedBlockingQueue<Integer> data;
Thread hilo;
public Productor(LinkedBlockingQueue<Integer> l) {
this.data = l;
Lanzando thread en el constructor
hilo = new Thread (this);
hilo.start();
}
public void run() {
try {
for(int x=0;;x++) {
data.put(new Integer(x)); //bloqueo si no hay hueco
System.out.println("Insertando "+x);
}
import java.util.concurrent.*;
}
public class Consumidor implements Runnable {
catch(InterruptedException e){}
LinkedBlockingQueue<Integer> data;
}
Thread hilo;
}
public Consumidor(LinkedBlockingQueue<Integer> l) {
this.data = l;
hilo = new Thread (this);
hilo.start();

Ejemplo de
productor/consumidor
usando
LinkedBlockkingQueue

}
public void run() {
try {
for(;;) //bloquea a hilo consumidor si no hay datos
System.out.println("Extrayendo "+data.take().intValue());
}
catch(InterruptedException e){}
}
}

public class SynchronousQueue<E> extends AbstractQueue<E> implements


BlockingQueue<E>, Serializable
A blocking queue in which each insert operation must wait for a corresponding remove
operation by another thread, and vice versa.
A synchronous queue does not have any internal capacity, not even a capacity of one.
This queue does not permit null elements.
Synchronous queues are similar to rendezvous channels used in CSP and Ada.
This class supports an optional fairness policy for ordering waiting producer and
consumer threads. By default, this ordering is not guaranteed. However, a queue
constructed with fairness set to true grants threads access in FIFO order.
This class and its iterator implement all of the optional methods of
the Collection and Iterator interfaces.
This class is a member of the Java Collections Framework.

SynchronousQueue<E>
import java.util.*;
import java.util.concurrent.*;
class Consumer implements Runnable{
class Producer implements Runnable{
private BlockingQueue<String> drop;
private BlockingQueue<String> drop;
List<String> messages = Arrays.asList(
Mensaje 1",
Mensaje 2",
"Mensaje 3",
"Mensaje 4");
public Producer(BlockingQueue<String> d) {
this.drop = d;
}
public void run() {
try
{
for (String s : messages)
drop.put(s);
drop.put("DONE");
}
catch (InterruptedException intEx)
{
System.out.println("Interrupted! " +
"Last one out, turn out the lights!");
}
}
}

public Consumer(BlockingQueue<String> d) {
this.drop = d;
}
public void run() {
try
{
String msg = null;
while (!((msg = drop.take()).equals("DONE")))
System.out.println(msg);
}
catch (InterruptedException intEx)
{
System.out.println("Interrupted! " +
"Last one out, turn out the lights!");
}
}
}
public class SynQApp{
public static void main(String[] args) {
BlockingQueue<String> drop =
new SynchronousQueue<String>();
(new Thread(new Producer(drop))).start();
(new Thread(new Consumer(drop))).start();
}
}

SynchronousQueue<E>

Modifier and Type


void
boolean
boolean
int
int
boolean
Iterator<E>
boolean
boolean
E
E
E
void
int
boolean
boolean
boolean
int
E
Object[]
<T> T[]

Method and Description


clear()Does nothing.
contains(Object o)Always returns false.
containsAll(Collection<?> c)Returns false unless the given collection is empty.
drainTo(Collection<? super E> c)Removes all available elements from this queue and adds them to the
given collection.
drainTo(Collection<? super E> c, int maxElements)Removes at most the given number of available
elements from this queue and adds them to the given collection.
isEmpty()Always returns true.
iterator()Returns an empty iterator in which hasNext always returns false.
offer(E e)Inserts the specified element into this queue, if another thread is waiting to receive it.
offer(E o, long timeout, TimeUnit unit)Inserts the specified element into this queue, waiting if necessary
up to the specified wait time for another thread to receive it.
peek()Always returns null.
poll()Retrieves and removes the head of this queue, if another thread is currently making an element
available.
poll(long timeout, TimeUnit unit)Retrieves and removes the head of this queue, waiting if necessary up
to the specified wait time, for another thread to insert it.
put(E o)Adds the specified element to this queue, waiting if necessary for another thread to receive it.
remainingCapacity()Always returns zero.
remove(Object o)Always returns false.
removeAll(Collection<?> c)Always returns false.
retainAll(Collection<?> c)Always returns false.
size()Always returns zero.
take()Retrieves and removes the head of this queue, waiting if necessary for another thread to insert it.
toArray()Returns a zero-length array.
toArray(T[] a)Sets the zeroeth element of the specified array to null (if the array has non-zero length)
and returns it.

public class Exchanger<V>


A synchronization point at which threads can pair and swap elements within pairs.
Each thread presents some object on entry to the exchange method, matches with a
partner thread, and receives its partner's object on return. An Exchanger may be
viewed as a bidirectional form of a SynchronousQueue.
Exchangers may be useful in applications such as genetic algorithms and pipeline
designs.
Sample Usage: Here are the highlights of a class that uses an Exchanger to swap
buffers between threads so that the thread filling the buffer gets a freshly emptied one
when it needs it, handing off the filled one to the thread emptying the buffer.

Exchanger<V>
class FillAndEmpty {
Exchanger<DataBuffer> exchanger = new Exchanger<DataBuffer>();
DataBuffer initialEmptyBuffer = ... a made-up type
DataBuffer initialFullBuffer = ...
class FillingLoop implements Runnable {
public void run() {
DataBuffer currentBuffer = initialEmptyBuffer;
try {
while (currentBuffer != null) {
addToBuffer(currentBuffer);
if (currentBuffer.isFull())
currentBuffer = exchanger.exchange(currentBuffer);
}
} catch (InterruptedException ex)
class EmptyingLoop implements Runnable {
{ ... handle ... }
public void run() {
}
DataBuffer currentBuffer = initialFullBuffer;
}
try {
while (currentBuffer != null) {
takeFromBuffer(currentBuffer);
if (currentBuffer.isEmpty())
currentBuffer = exchanger.exchange(currentBuffer);
}
} catch (InterruptedException ex) { ... handle ...}
}
}
void start() {
new Thread(new FillingLoop()).start();
new Thread(new EmptyingLoop()).start();
}
}

Exchanger<V>

Constructors
Constructor and Description
Exchanger()Creates a new Exchanger.

Methods
Modifier and Type
V

Method and Description


exchange(V x)Waits for another thread to arrive at this exchange point
(unless the current thread is interrupted), and then transfers the given object
to it, receiving its object in return.
exchange(V x, long timeout, TimeUnit unit)Waits for another thread to arrive
at this exchange point (unless the current thread is interrupted or the
specified waiting time elapses), and then transfers the given object to it,
receiving its object in return.

public class CountDownLatch


A synchronization aid that allows one or more threads to wait until a set of operations
being performed in other threads completes.
A CountDownLatch is initialized with a given count.
The await methods block until the current count reaches zero due to invocations of
the countDown() method, after which all waiting threads are released and any
subsequent invocations of await return immediately.

Ejemplo:
Tengo un thread maestro y varios esclavos. Los esclavos no pueden empezar hasta
que el maestro lo diga. Por otra parte, el maestro tiene que esperar a que todos los
esclavos terminen

class Driver { // ...


void main() throws InterruptedException {
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(N);
for (int i = 0; i < N; ++i) // create and start threads
new Thread(new Worker(startSignal, doneSignal)).start();
doSomethingElse();
startSignal.countDown();
doSomethingElse();
doneSignal.await();

// don't let run yet


// let all threads proceed
// wait for all to finish

}
}

class Worker implements Runnable {


private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
public void run() {
try {
startSignal.await();
doWork();
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
void doWork() { ... }
}

java.util.concurrent.CyclicBarrier
public class CyclicBarrier
A synchronization aid that allows a set of threads to all wait for each other to reach
a common barrier point.
CyclicBarriers are useful in programs involving a fixed sized party of threads that
must occasionally wait for each other.
The barrier is called cyclic because it can be re-used after the waiting threads are
released.
A CyclicBarrier supports an optional Runnable command that is run once per barrier
point, after the last thread in the party arrives, but before any threads are released.
This barrier action is useful for updating shared-state before any of the parties
continue.
Sample usage: Here is an example of using a barrier in a parallel decomposition
design:

CyclicBarrier
class Solver {
final int N;
final float[][] data;
final CyclicBarrier barrier;
class Worker implements Runnable {
int myRow;
Worker(int row) { myRow = row; }
public void run() {
while (!done()) {
processRow(myRow);
try {
barrier.await();
} catch (InterruptedException ex) {
return;
} catch (BrokenBarrierException ex) {
return;
}
}
}
}

public Solver(float[][] matrix) {


data = matrix;
N = matrix.length;
barrier = new CyclicBarrier(N,
new Runnable() {
public void run() {
mergeRows(...);
}
});
for (int i = 0; i < N; ++i)
new Thread(newWorker(i)).start();
waitUntilDone();
}
}

CyclicBarrier

Constructors
Constructor and Description
CyclicBarrier(int parties) Creates a new CyclicBarrier that will trip when the given number of parties
(threads) are waiting upon it, and does not perform a predefined action when the barrier is tripped.
CyclicBarrier(int parties, Runnable barrierAction)Creates a new CyclicBarrier that will trip when the
given number of parties (threads) are waiting upon it, and which will execute the given barrier action
when the barrier is tripped, performed by the last thread entering the barrier.
Methods
Modifier and Type
int
int
int
int
boolean
void

Method and Description


await()Waits until all parties have invoked await on this barrier.
await(long timeout, TimeUnit unit)Waits until all parties have
invoked await on this barrier, or the specified waiting time elapses.
getNumberWaiting()Returns the number of parties currently waiting at the
barrier.
getParties()Returns the number of parties required to trip this barrier.
isBroken()Queries if this barrier is in a broken state.
reset()Resets the barrier to its initial state

You might also like