In class Semaphore
tryAcquire() and tryAcquire(n)
each call Semaphore.Sync.nonfairTryAcquireShared(1)
which appears to busy wait until enough permits are available,
returning immediately if there are enough available. Therefore
barging is possible.
tryAcquire(t, unit) and tryAcquire(n, t, unit)
each call java.util.concurrent.locks.AbstractQueuedSynchronizer
.tryAcquireSharedNanos(1, unit.toNanos(t))
which calls AbstractQueuedSynchronizer.doAcquireShared
which clearly queues the thread if not enough permits are available.
Therefore no barging is possible, even if the timeout is 0.
package edu.lmu.cs.demos.threads;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class Summer {
/**
* Returns the sum of all the values in the given integer array.
*/
public static int sum(int[] data, int partitions) {
// Clamp the number of partitions to something sensible.
partitions = Math.max(1, Math.min(data.length, partitions));
/**
* A result object has a field for both the sum of the array
* and a field for any exception that might have occurred.
* These are wrapped in an object so they can be modified by
* inner classes, since in Java inner threads can only access
* final fields of containing classes.
*/
class Result {
int value = 0;
Exception exception;
void increment(int delta) {value += delta;}
}
final Result result = new Result();
/**
* A thread to sum partitions. The constructor takes in a barrier
* because the thread and the barrier depend on each other, and
* Java is picky about defining one before the other.
*/
class RangeSummer extends Thread {
private int[] data;
private int low;
private int high;
private CyclicBarrier barrier;
private int value = 0;
public RangeSummer(int[] data, int low, int high,
CyclicBarrier barrier) {
this.data = data;
this.low = low;
this.high = high;
this.barrier = barrier;
}
public void run() {
for (int i = low; i < high; i++) {
value += data[i];
}
try {
barrier.await();
} catch (InterruptedException e) {
result.exception = e;
} catch (BrokenBarrierException e) {
result.exception = e;
}
}
}
final RangeSummer[] rangeSummers = new RangeSummer[partitions];
// All threads plus the man thread wait on this barrier. Last one
// to arrive totals up all the partial sums.
CyclicBarrier barrier = new CyclicBarrier(partitions+1, new Runnable() {
public void run() {
for (RangeSummer r : rangeSummers) {
result.increment(r.value);
}
}
});
// Launch the worker threads
int partitionSize = data.length / partitions;
for (int low = 0, i = 0; i < partitions; i++, low += partitionSize) {
int high = i == partitions-1 ? data.length : low + partitionSize;
rangeSummers[i] = new RangeSummer(data, low, high, barrier);
rangeSummers[i].start();
}
// Wait for all the workers to finish
try {
barrier.await();
} catch (InterruptedException e) {
result.exception = e;
} catch (BrokenBarrierException e) {
result.exception = e;
}
// Now we either got a real sum or a problem was recorded
if (result.exception != null) {
throw new RuntimeException(result.exception);
}
return result.value;
}
}
package edu.lmu.cs.demos.threads;
import java.util.Arrays;
import junit.framework.TestCase;
import junit.textui.TestRunner;
public class SumTester extends TestCase {
public void testSum() throws InterruptedException {
int[] a = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
assertEquals(Summer.sum(a, 1), 55);
assertEquals(Summer.sum(a, 2), 55);
assertEquals(Summer.sum(a, 3), 55);
assertEquals(Summer.sum(a, 4), 55);
assertEquals(Summer.sum(a, 5), 55);
assertEquals(Summer.sum(a, 6), 55);
assertEquals(Summer.sum(a, 7), 55);
assertEquals(Summer.sum(a, 8), 55);
assertEquals(Summer.sum(a, 9), 55);
assertEquals(Summer.sum(a, 10), 55);
a = new int[20000];
Arrays.fill(a, 7);
assertEquals(Summer.sum(a, 1), 140000);
assertEquals(Summer.sum(a, 459), 140000);
assertEquals(Summer.sum(a, 920), 140000);
}
public static void main(String[] args) {
TestRunner.run(SumTester.class);
}
}
Sorry, I didn't do the graphics...
package edu.lmu.cs.demos.threads;
import java.awt.GridLayout;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JFrame;
import javax.swing.JLabel;
/**
* A little simulation of the famous "Dining Philosophers". To prevent
* deadlock only four philosophers will be allowed to sit in the dining room
* at any given time. Interesting events in the simulation are written to
* the main window which is a trivial dialog box. (The GUI is very crude
* because this application illustrates threads and synchronization and not
* how to layout a fine interface). To allow the simulation to exit
* gracefully philosophers only eat fifteen times.
*
* The simulation is made up of the following classes:
*
* DiningPhilosophers the public class containing the main() method
* tion and the simulation objects (philosophers
* and chopsticks).
* Philosopher class for the philosophers.
* Chopstick class for the chopsticks.
* Table class for the table.
*/
public class DiningPhilosophers {
/**
* Here are the philosophers' names. To add a new philosopher,
* just add a new name to the array. To make the program even
* more flexible read in the philosophers' names from a properties file.
*/
static String[] names = {"Plato", "Rand", "Russell", "Leibniz", "Church"};
/**
* Runs the simuation.
*/
public static void main(String[] args) {
JFrame frame = new JFrame("Dining Philosophers");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new GridLayout(0, 2));
Chopstick[] c = new Chopstick[names.length];
for (int i = 0; i < c.length; i++) {
c[i] = new Chopstick();
}
for (int i = 0; i < names.length; i++) {
frame.getContentPane().add(new JLabel(names[i] + " "));
JLabel label = new JLabel();
frame.getContentPane().add(label);
new Philosopher(c[i], c[(i+1) % names.length], label);
}
frame.setSize(640, 200);
frame.setVisible(true);
}
}
/**
* The active objects in the simulation are the philosophers,
* so we make them runnable.
*/
class Philosopher implements Runnable {
private Chopstick left, right;
private JLabel message;
private static Table table = new Table();
/**
* The constructor assigns the chopsticks and a Label for
* writing simulation messages into.
*/
public Philosopher(Chopstick left, Chopstick right, JLabel message) {
this.left = left;
this.right = right;
this.message = message;
new Thread(this).start();
}
/**
* Do something for a random duration between minDelay and maxDelay.
*/
private void perform(String text, int minDelay, int maxDelay) {
message.setText(text);
try {
Thread.sleep((int)(Math.random() * (maxDelay-minDelay) + minDelay));
} catch (InterruptedException ignored) {
}
}
/**
* Philosophers have boring lives: They think and eat, think
* and eat, think and eat, ... and then they die!
*/
public void run() {
message.setText("has just been born");
for (int timesEaten = 0; timesEaten < 15; timesEaten++) {
table.sitDownAt();
perform("has sat down and is now thinking", 1000, 4000);
left.pickUp();
message.setText("is holding left, waiting for right");
right.pickUp();
perform("Eating", 1000, 5000);
left.putDown();
right.putDown();
perform("has put both chopsticks down and is leaving", 1000, 2000);
table.getUpFrom();
}
message.setText("is dead");
}
}
/**
* Chopsticks are shared resources which are explicitly locked
* and unlocked, because the implementation of this class was part
* of a homework assignment. Initially the chopstick is down, and
* philosophers can pick them up and put them down. Of course they
* can only be picked up when not already up, and put down when they
* are not already down.
*/
class Chopstick {
private ReentrantLock lock = new ReentrantLock();
public void pickUp() {
lock.lock();
}
public void putDown() {
lock.unlock();
}
}
/**
* A table that has one less seat than there are philosophers.
* Philosophers call sitDownAt() to obtain a seat and call getUpFrom()
* to free it. Note that a philosopher calling sitDownAt() with only
* one empty seat will have to wait for one to be freed. Philosophers
* are horribly stubborn; when waiting for a seat they will refuse
* to be interrupted.
*/
class Table {
private final Semaphore seats =
new Semaphore(DiningPhilosophers.names.length);
public void sitDownAt() {
seats.acquireUninterruptibly();
}
public void getUpFrom() {
seats.release();
}
}
package edu.lmu.cs.demos.threads;
import java.awt.BorderLayout;
import javax.swing.JFrame;
public class MandelbrotDemo {
/**
* Places a MandlebrotPanel inside an application main frame and
* shows (runs) it.
*/
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Mandlebrot Set");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.setLocationRelativeTo(null);
frame.setLayout(new BorderLayout());
MandelbrotPanel panel = new MandelbrotPanel();
frame.getContentPane().add(panel);
frame.setResizable(false);
frame.setVisible(true);
panel.generateWithThreadPool();
frame.setTitle(frame.getTitle() + " - finished");
}
}
package edu.lmu.cs.demos.threads;
import java.awt.Color;
import java.awt.Graphics;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.swing.JPanel;
/**
* A wimpy panel for drawing a Mandelbrot set.
*/
public class MandelbrotPanel extends JPanel {
double left = -2.5;
double right = 1.5;
double bottom = -1.5;
double top = 1.5;
int maxIterations = 150;
public void setBounds(double l, double r, double b, double t) {
this.left = l;
this.right = r;
this.bottom = b;
this.top = t;
}
public void setMaxIterations(int maxIterations) {
this.maxIterations = maxIterations;
}
public void generate() {
int width = this.getWidth();
int height = this.getHeight();
double dx = (right - left) / width;
double dy = (bottom - top) / height;
Graphics g = getGraphics();
double y = top;
for (int row = 0; row < height; row++, y += dy) {
double x = left;
for (int col = 0; col < width; col++, x += dx) {
g.setColor(colorFor(x, y));
g.drawLine(col, row, col, row);
}
}
}
/**
* Generates the picture using a thread pool running tasks that are
* each responsible for coloring a single pixel.
*/
public void generateWithThreadPool() throws InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(24);
int width = this.getWidth();
int height = this.getHeight();
double dx = (right - left) / width;
double dy = (bottom - top) / height;
Graphics g = getGraphics();
double y = top;
for (int row = 0; row < height; row++, y += dy) {
double x = left;
for (int col = 0; col < width; col++, x += dx) {
pool.execute(new MandelbrotPixelPlotter(col, row, x, y, g));
}
}
// Wait for an orderly shutdown before returning.
pool.shutdown();
pool.awaitTermination(30000, TimeUnit.SECONDS);
}
/**
* A task that colors a pixel.
*/
private class MandelbrotPixelPlotter implements Runnable {
int col, row;
double x, y;
Graphics g;
public MandelbrotPixelPlotter(int col, int row, double x, double y,
Graphics g) {
this.col = col; this.row = row; this.x = x; this.y = y;
this.g = g;
}
public void run() {
g.setColor(colorFor(x, y));
g.drawLine(col, row, col, row);
}
}
/**
* Determines the color of the point x+yi in the Mandlebrot
* set, based on the value of maxIterations. For now, a hard-coded
* gradient is used; this should be parameterized.
*/
private Color colorFor(double x, double y) {
double zx = 0;
double zy = 0;
for (int i = 0; i < maxIterations; i++) {
double cx = zx * zx - zy * zy + x;
double cy = 2 * zx * zy + y;
zx = cx;
zy = cy;
if (cx * cx + cy * cy >= 4.0) {
int shade = 255 - (255 * i / maxIterations);
return new Color(shade, shade, shade);
}
}
return Color.BLACK;
}
}