Slide navigation: Forward with space bar, → arrow key, or PgDn. Backwards with ← or PgUp.
ExecutorService to map tasks to threads
ExecutorService service = Executors.newCachedThreadPool();or
int processors = Runtime.getRuntime().availableProcessors(); ExecutorService service = Executors.newFixedThreadPool(processors);
RunnableRunnable has one method
void run()
run methodRunnable object to ExecutorService
Runnable task = () -> { task instructions };
service.execute(task)
public static Runnable greeter(String greeting, int repetitions)
{
return () ->
{
for (int i = 0; i < repetitions; i++)
System.out.println(greeting);
};
}
Runnable instances
Runnable r1 = greeter("Hello", 100);
Runnable r2 = greeter("Goodbye", 100);ExecutorService
ExecutorService service = Executors.newCachedThreadPool(); service.execute(r1); service.execute(r2); service.shutdown();
Hello Hello Hello Goodbye ... Goodbye Goodbye Hello ...
Callable<V> for a task that yields a result
public interface Callable<V>
{
V call() throws Exception;
}Callable by submitting it to an ExecutorService
Callable<V> task = . . .; Future<V> resultFuture = service.submit(task);
Future<V>—an object that will yield a value in the future.get method blocks until value is available:
V result = resultFuture.get()
List<Callable<V>> tasks = . . .;
List<Future<V>> resultFutures = service.invokeAll(tasks);
for (Future<V> resultFuture : resultFutures)
{
V result = resultFuture.get();
Incorporate result in the final result
}try
{
V result = service.invokeAny(tasks);
. . .
}
catch (ExecutionException ex)
{
// No task yielded a result
} run exitsstop methodinterruptt.interrupt() doesn't actually interrupt t; just sets a flag
run method
Thread.currentThread().isInterrupted()sleep, wait throw InterruptedException when thread interruptedInterruptedException and react to interruptionrun when sensing interruptionpublic class MyRunnable implements Runnable
{
public void run()
{
try
{
while (...)
{
do work
Thread.sleep(...);
}
}
catch (InterruptedException e)
{
// terminate thread
}
}
}
for (int i = 0; i < repetitions; i++) queue.add(greeting);
int count1 = 0;
int count2 = 0;
for (int i = 0; i < repetitions; i++)
{
String greeting = queue.remove();
if (greeting1.equals(greeting)) count1++;
else if (greeting2.equals(greeting)) count2++;
}
System.out.println(greeting1 + ": " + count1);
System.out.println(greeting2 + ": " + count2);
public static void main(String[] args)
{
int n = 1000;
BoundedQueue<String> q = new BoundedQueue<>(2 * n);
ExecutorService service = Executors.newCachedThreadPool();
Runnable p1 = producer("Hello", q, n);
Runnable p2 = producer("Goodbye", q, n);
Runnable c = consumer("Hello", "Goodbye", q, 2 * n);
service.execute(p1);
service.execute(p2);
service.execute(c);
service.shutdown();
}
Hello: 1000 Goodbye: 1000
Hello: 487 Goodbye: 807
Why is the program corrupted?
add and executes
elements[tail] = anObject;add and executes
elements[tail] = anObject;
tail++;tail++;
java.util.concurrent.Lock interface type, usually ReentrantLockaLock = new ReentrantLock();
. . .
aLock.lock();
try
{
protected code
}
finally
{
aLock.unlock();
}
add and acquires lock, then executes
elements[tail] = anObject;add and tries to acquire lock, but it is blocked
tail++;add, releases lock
add, removeif (!queue.isFull()) queue.add(...);
can still be interruptedadd method
public void add(E newValue)
{
queueLock.lock();
try
{
while (queue is full)
wait for more space
. . .
}
finally { qeueLock.unlock(); }
}
removeprivate Lock queueLock = new ReentrantLock(); private Condition spaceAvailableCondition = queueLock.newCondition();
await when condition is not fulfilled:
public void add(E newValue)
{
. . .
while (size == elements.length)
spaceAvailableCondition.await();
. . .
}
signalAll on the same condition objectpublic E remove()
{
. . .
E r = elements[head];
. . .
spaceAvailableCondition.signalAll(); // Unblock waiting threads
return r;
}
synchronized method acquires lock of implicit parametersynchronized method releases lockLock objects
public class BoundedQueue<E>
{
public synchronized void add(E newValue) { . . . }
public synchronized E remove() { . . . }
. . .
}
Object.wait blocks current thread and adds it to wait set
Object.notifyAll unblocks waiting threads
public synchronized void add(E newValue)
throws InterruptedException
{
while (size == elements.length) wait();
elements[tail] = anObject;
. . .
notifyAll(); // notifies threads waiting to remove elements
}
synchronized (obj)
{
critical section
}Map<String, Integer> map = . . .
synchronized (map)
{
Integer value = map.get(key);
if (value == null) map.put(key, 1);
else map.put(key, value + 1);
}
ConcurrentHashMap insteadBoundedQueue in productionjava.util.concurrent has professionally implemented threadsafe classesArrayBlockingQueue (bounded), LinkedBlockingQueue (unbounded)BlockingQueue interfaceput, take block if full/emptyadd, remove throw exception if full/empty offer, poll return error code if full/empty (less useful in concurrent programs)
compare methodComparator<Double> comp = (d1, d2) ->
{
sleep
return comparison result
};
java.util.concurrent"Run" or "Step" to queuetake on the queue, blocks if no string inserted