concurrent-dfsg-1.3.4/ 0000755 0001750 0001750 00000000000 10202637436 015047 5 ustar wbaer wbaer 0000000 0000000 concurrent-dfsg-1.3.4/taskDemo/ 0000755 0001750 0001750 00000000000 10202634623 016611 5 ustar wbaer wbaer 0000000 0000000 concurrent-dfsg-1.3.4/taskDemo/Microscope.java 0000644 0001750 0001750 00000074443 10202157355 021575 0 ustar wbaer wbaer 0000000 0000000 import java.awt.*; import javax.swing.*; import java.util.*; import java.awt.event.*; import javax.swing.event.*; import EDU.oswego.cs.dl.util.concurrent.*; /** * Microscope implements a version of the 7th Guest * game found looking in the Microscope in the laboratory. * See * Microscope version for instructions. *
* The code has been mangled beyond recognition
* as a test of the FJTasks package.
**/
public class Microscope extends JPanel {
/*
* If true, the move finder uses a repeatable evaluation
* strategy, so all self-play games at same level have same outcome.
* This is useful for testing purposes, but much less fun to watch.
*/
static boolean DETERMINISTIC = false;
// Command-line parameters
static int nprocs;
static int lookAheads = 3;
static boolean autostart = false;
public static void main(String[] args) {
try {
nprocs = Integer.parseInt(args[0]);
if (args.length > 1) {
autostart = true;
lookAheads = Integer.parseInt(args[1]);
DETERMINISTIC = true;
}
}
catch (Exception e) {
System.out.println("Usage: java Microscope
* Boards are not immutable, but are never passed around across
* threads (instead new ones are constructed), so don't
* need any synch.
**/
static final class Board {
/*
First, some Constants and utilities that might as well be here
*/
public static final int RANKS = 7;
public static final int CELLS = RANKS * RANKS;
static final long FULL = (1L << CELLS) - 1;
// The finder uses a spare bit to remember whose move it is.
static final long BLUEBIT = (1L << CELLS);
// Bits representing the adjacent cells for every position
static final long[] adjacentMasks = new long[CELLS];
// bit pattern associated with each tile
static final long[] cellBits = new long[CELLS];
// locations of all cells reachable by a jump for every position
static final byte[][] jumpDestinations = new byte[CELLS][];
// initialize tables
static {
byte[] dests = new byte[CELLS];
for (int j = 0; j < RANKS; ++j) {
for (int i = 0; i < RANKS; ++i) {
int k = i + j * RANKS;
long nmask = 0;
int jumpCount = 0;
for (int c = j-2; c <= j+2; ++c) {
for (int r = i-2; r <= i+2; ++r) {
if (c >= 0 && c < RANKS &&
r >= 0 && r < RANKS) {
int cellIndex = r + c * RANKS;
if (r == i-2 || r == i+2 || c == j-2 || c == j+2) {
dests[jumpCount++] = (byte)cellIndex;
}
else if (!(r == i && c == j)) {
nmask |= 1L << cellIndex;
}
}
}
}
adjacentMasks[k] = nmask;
cellBits[k] = 1L << k;
jumpDestinations[k] = new byte[jumpCount];
for (int l = 0; l < jumpCount; ++l)
jumpDestinations[k][l] = dests[l];
}
}
}
public static boolean inBounds(int row, int col) {
return (0 <= row) && (row < RANKS) && (0 <= col) && (col < RANKS);
}
// The representation
long blue_; // bit vector; true if occupied by blue
long green_; // same for green;
// constructors and intializers:
public Board() { blue_ = 0L; green_ = 0L; }
public Board(Board b) { blue_ = b.blue_; green_ = b.green_; }
public Board(long b, long g) { blue_ = b; green_ = g; }
public void copyState(Board b) {
blue_ = b.blue_;
green_ = b.green_;
}
void reset() {
blue_ = 0L; green_ = 0L;
}
long getBlue() { return blue_; }
long getGreen() { return green_; }
public Player occupant(int row, int col) {
if ((0 <= row) && (row < RANKS) && (0 <= col) && (col < RANKS)) {
long m = 1L << (row + col * RANKS);
if ((blue_ & m) != 0L) return Player.Blue;
else if ((green_ &m) != 0L) return Player.Green;
else return Player.Empty;
}
else
return Player.Illegal;
}
// place a tile without taking opponent tiles
public void occupy(Player player, int row, int col) {
long m = 1L << (row + col * RANKS);
long nm = ~m;
if (player.code_ == Player.BLUE) {
blue_ |= m;
green_ &= nm;
}
else if (player.code_ == Player.GREEN) {
blue_ &= nm;
green_ |= m;
}
else {
blue_ &= nm;
green_ &= nm;
}
}
public void unoccupy(int row, int col) {
long nm = ~(1L << (row + col * RANKS));
blue_ &= nm;
green_ &= nm;
}
// place a tile, taking all adjacent tiles of opponent
public void take(Player player, int row, int col) {
int k = (row + col * RANKS);
long dest = 1L << k;
long nbrMask = adjacentMasks[k];
long sourceBlue = blue_;
long sourceGreen = green_;
if (player.code_ == Player.BLUE) {
blue_ = sourceBlue | dest | (sourceGreen & nbrMask);
green_ = sourceGreen & ~(sourceGreen & nbrMask);
}
else {
blue_ = sourceBlue & ~(sourceBlue & nbrMask);
green_ = sourceGreen | dest | (sourceBlue & nbrMask);
}
}
public boolean gameOver() {
return
(((blue_ | green_) & FULL) == FULL) ||
((blue_ & ~BLUEBIT) == 0) ||
((green_ & ~BLUEBIT) == 0);
}
public int score(Player player) {
if (player.isBlue()) {
return score(blue_, green_);
}
else {
return score(green_, blue_);
}
}
static int score(long b, long g) {
// much faster by splitting into ints
// and using clever shift-based bit counter
int lb = (int)(b & ((1L << 32) - 1));
int hb = ((int)(b >>> 32)) & ((1 << (CELLS - 32)) - 1);
lb -= (0xaaaaaaaa & lb) >>> 1;
lb = (lb & 0x33333333) + ((lb >>> 2) & 0x33333333);
lb = lb + (lb >>> 4) & 0x0f0f0f0f;
lb += lb >>> 8;
lb += lb >>> 16;
hb -= (0xaaaaaaaa & hb) >>> 1;
hb = (hb & 0x33333333) + ((hb >>> 2) & 0x33333333);
hb = hb + (hb >>> 4) & 0x0f0f0f0f;
hb += hb >>> 8;
hb += hb >>> 16;
hb = ((lb + hb) & 0xff);
int lg = (int)(g & ((1L << 32) - 1));
int hg = ((int)(g >>> 32)) & ((1 << (CELLS - 32)) - 1);
lg -= (0xaaaaaaaa & lg) >>> 1;
lg = (lg & 0x33333333) + ((lg >>> 2) & 0x33333333);
lg = lg + (lg >>> 4) & 0x0f0f0f0f;
lg += lg >>> 8;
lg += lg >>> 16;
hg -= (0xaaaaaaaa & hg) >>> 1;
hg = (hg & 0x33333333) + ((hg >>> 2) & 0x33333333);
hg = hg + (hg >>> 4) & 0x0f0f0f0f;
hg += hg >>> 8;
hg += hg >>> 16;
return hb - ((lg + hg) & 0xff);
}
static int slowscore(long b, long g) {
int score = 0;
for (int l = 0; l < CELLS; ++l) {
score += (int)(b & 1);
b >>>= 1;
score -= (int)(g & 1);
g >>>= 1;
}
return score;
}
}
/**
* Moves represent transitions across Board states
**/
static final class Move {
static final int NO_VALUE = -1; // row/col value if not yet set
static final int PASS_VALUE = -2; // special value for pass moves
// utilities for classifying moves
public static boolean twoFrom(int a, int b) {
return (a - b == 2) || (b - a == 2);
}
public static boolean withinTwo(int a, int b) {
int diff = a - b; return -2 <= diff && diff <= 2;
}
// representations
int fromRow;
int fromCol;
int toRow;
int toCol;
Player player_;
Board board_;
boolean committed = false; // true if board reflects move
// constructors and intializers
public Move(Player turn, Board board) {
fromRow = NO_VALUE; fromCol = NO_VALUE;
toRow = NO_VALUE; toCol = NO_VALUE;
player_ = turn;
board_ = board;
}
public Move(Player turn, Board board, boolean isCommitted) {
fromRow = NO_VALUE; fromCol = NO_VALUE;
toRow = NO_VALUE; toCol = NO_VALUE;
player_ = turn;
board_ = board;
committed = isCommitted;
}
synchronized void reset() {
fromRow = NO_VALUE;
fromCol = NO_VALUE;
toRow = NO_VALUE;
toCol = NO_VALUE;
}
// setters:
synchronized void player(Player p) { player_ = p; }
synchronized void board(Board b) { board_ = b; }
synchronized void from(int sr, int sc) { fromRow = sr; fromCol = sc; }
synchronized void to(int dr, int dc) { toRow = dr; toCol = dc; }
// accessors:
synchronized boolean isFrom(int r, int c) {
return fromRow== r && fromCol == c;
}
synchronized boolean isTo(int r, int c) {
return toRow == r && toCol == c;
}
synchronized Board board() {
return board_;
}
synchronized Player player() {
return player_;
}
// status checks:
synchronized boolean isPass() { // is this a `pass' move?
return (toRow == PASS_VALUE || fromRow == PASS_VALUE);
}
synchronized boolean isJump() {
return
(fromRow - toRow == 2) || (toRow - fromRow == 2) ||
(fromCol - toCol == 2) || (toCol - fromCol == 2);
}
synchronized boolean hasFrom() { // is from set?
return fromRow != NO_VALUE && fromCol != NO_VALUE;
}
synchronized boolean hasTo() { // is to set?
return toRow != NO_VALUE && toCol != NO_VALUE;
}
synchronized boolean possibleTo(int r, int c) { // is (r, c) a legal `to'?
return hasFrom() &&
withinTwo(fromRow, r) &&
withinTwo(fromCol, c) &&
board_.occupant(r, c).isEmpty();
}
synchronized boolean isLegal() {
if (isPass())
return true;
else if (!board_.occupant(toRow, toCol).isEmpty())
return false;
else if (!board_.occupant(fromRow, fromCol).same(player_))
return false;
else if (!(withinTwo(fromRow, toRow) && withinTwo(fromCol, toCol)))
return false;
else
return true;
}
synchronized void commit() { // update board to reflect move
if (!committed) {
committed = true;
if (isLegal() && !isPass()) {
if (isJump()) board_.occupy(Player.Empty, fromRow, fromCol);
board_.take(player_, toRow, toCol);
}
}
}
}
/**
* Mover is an abstract class to simplify code dealing with
* either user moves or auto moves.
**/
static abstract class Mover {
// caller for move callbacks
protected Microscope game;
protected Mover(Microscope ap) { game = ap; }
// start a turn as player on given board
public abstract void startTurn(Board b, Player p);
// cancel current partial move
public abstract void cancel();
// return true if move not yet ready
public abstract boolean placing();
}
/**
* User builds moves via instructions/clicks by users
**/
static class User extends Mover {
private Move current;
public User(Microscope ap) { super(ap); current = null; }
public synchronized void startTurn(Board b, Player p) {
current = new Move(p, b);
}
public boolean placing() {
return current != null && current.hasFrom() && !current.hasTo();
}
public synchronized void cancel() {
if (current != null) {
current.reset();
current = null;
}
}
public synchronized void choose(int row, int col) {
if (current != null) {
if (row == Move.PASS_VALUE) {
current.from(row, col);
game.move(current, this);
current = null;
}
else if (!current.hasFrom()) {
if (current.board().occupant(row, col).same(current.player())) {
current.from(row, col);
}
}
else {
current.to(row, col);
game.move(current, this);
current = null;
}
}
}
public synchronized boolean canMoveTo(int row, int col) {
return placing() && current.possibleTo(row, col);
}
public synchronized boolean hasMovedFrom(int row, int col) {
return current != null && current.isFrom(row, col);
}
}
/**
* AutoMover constructs Finders that compute actual moves
**/
static class AutoMover extends Mover {
FJTaskRunnerGroup group = null;
boolean cancelled = false;
RootFinder currentFinder = null;
public AutoMover(Microscope ap) {
super(ap);
}
public synchronized boolean placing() {
return currentFinder != null;
}
synchronized void stopPlacing() {
currentFinder = null;
}
public synchronized void cancel() {
if (placing()) {
currentFinder.cancel();
stopPlacing();
}
}
public synchronized void startTurn(Board board, Player player) {
try {
if (group == null) {
group = new FJTaskRunnerGroup(Microscope.nprocs);
}
if (!placing()) {
currentFinder = new RootFinder(board, player,
Microscope.lookAheads, this);
group.execute(currentFinder);
}
}
catch (InterruptedException ex) {
stopPlacing();
}
}
public void stats() {
if (group != null) group.stats();
}
synchronized void relay(Move move) { // relay callback from finder
if (placing()) {
stopPlacing();
game.move(move, this);
}
}
}
/**
* Implements a classic all-possible-move search algorith using FJTasks.
* The move finder is not all that smart. Among other possible
* improvements, it could keep a cache of explored moves and
* avoid repeating them. This would likely speed it up since
* most expansions are duplicates of others. It could also be changed to
* prune moves, although this is unlikely to work well without
* better partial evaluation functions.
**/
static class Finder extends FJTask {
static final int NOMOVE = Integer.MIN_VALUE;
static final int LOSE = NOMOVE+1;
static final int WIN = -LOSE;
final long ours; // bits for our tiles
final long theirs; // bits for opponent tiles
final int level; // current number of lookAheads
final Finder next; // Each Finder is placed in a linked list by parent
// Assigned once; must be volatile since accessed by parents
volatile int bestScore;
Finder(long ours, long theirs, int level, Finder next) {
this.ours = ours;
this.theirs = theirs;
this.level = level;
this.next = next;
}
public final void run() {
// Handle sure wins and losses here
if ((ours & ~Board.BLUEBIT) == 0)
bestScore = LOSE;
else if ((theirs & ~Board.BLUEBIT) == 0)
bestScore = WIN;
else if (((ours | theirs) & Board.FULL) == Board.FULL) {
int score = Board.score(ours, theirs);
if (score > 0) bestScore = WIN;
else if (score < 0) bestScore = LOSE;
else bestScore = 0;
}
else
search();
}
final void search() {
int best = NOMOVE; // For direct evaluation when level == 1
Finder forked = null; // list of forked subtasks when level > 1
long open = ~(ours | theirs); // currently empty cells
long here = 1; // travserse through bits
for (int k = 0; k < Board.CELLS; ++k, here <<= 1) {
if ((here & ours) != 0) {
/*
* Step through possible destinations to find jumps for this tile
*/
byte[] dests = Board.jumpDestinations[k];
for (int j = 0; j < dests.length; ++j) {
byte d = dests[j];
long dest = 1L << d;
if ( (dest & open) != 0) {
long adjacent = Board.adjacentMasks[d];
long nTheirs = theirs & ~adjacent;
long nOurs = (ours & ~here) | dest | (theirs & adjacent);
if (level > 1)
(forked = new Finder(nTheirs, nOurs, level-1, forked)).fork();
else {
int sc = Board.score(nOurs, nTheirs);
if (sc > best) best = sc;
}
}
}
}
else if ((here & open) != 0) {
/*
* If this cell is open, and is within 1 of one of our tiles,
* it can be taken in some copy move. It doesn't matter which
* of the adjacent cells is considered to be source of copy
* move
*/
long adjacent = Board.adjacentMasks[k];
if ((ours & adjacent) != 0) {
long nTheirs = theirs & ~adjacent;
long nOurs = ours | here | (theirs & adjacent);
if (level > 1)
(forked = new Finder(nTheirs, nOurs, level-1, forked)).fork();
else {
int sc = Board.score(nOurs, nTheirs);
if (sc > best) best = sc;
}
}
}
}
if (level > 1)
collect(forked);
else
bestScore = best;
}
/**
* Join all subtasks and evaluate moves. Default is sub-finder version.
* Overridden in RootFinder
**/
void collect(Finder forked) {
int best = NOMOVE;
while (forked != null) {
while (!forked.isDone()) { // interleave joins with cancel checks
if (isDone()) {
cancelAll(forked);
return;
}
else
yield();
}
int score = -forked.bestScore; // negate opponent score
if (score > best) {
best = score;
if (score >= WIN) {
cancelAll(forked.next);
break;
}
}
forked = forked.next;
}
bestScore = best;
}
/**
* Cancel all forked subtasks in list
**/
void cancelAll(Finder forked) {
while (forked != null) {
forked.cancel();
forked = forked.next;
}
}
}
/**
* Root Finder class -- wait out other finders and issue callback to game.
**/
static class RootFinder extends Finder {
final AutoMover automover;
final Player player;
RootFinder(Board board, Player p, int level, AutoMover automover) {
super( (p.isBlue()? (board.getBlue()| Board.BLUEBIT) : board.getGreen()),
(p.isBlue()? board.getGreen() : (board.getBlue()| Board.BLUEBIT)),
level,
null);
this.player = p;
this.automover = automover;
}
/**
* This differs from default version by recording
* and calling back with best move
**/
void collect(Finder forked) {
int best = NOMOVE;
Finder bestFinder = null;
while (forked != null) {
while (!forked.isDone()) {
if (isDone()) {
cancelAll(forked);
return;
}
else
yield();
}
int score = -forked.bestScore; // negate opponent score
if (bestFinder == null || score > best) {
best = score;
bestFinder = forked;
if (score >= WIN) {
cancelAll(forked.next);
break;
}
}
// Just for fun, introduce a little randomness via hashcodes
else if (score == best &&
!Microscope.DETERMINISTIC &&
(System.identityHashCode(forked) >
System.identityHashCode(bestFinder))) {
bestFinder = forked;
}
forked = forked.next;
}
Move move = null;
if (bestFinder != null) {
/*
Even though accessed here,
the ours and theirs vars of Finders do not
need to be volatile because they are immutably
established in constructors.
*/
long nextOurs = bestFinder.theirs;
long nextTheirs = bestFinder.ours;
long blue = (player.isBlue())? nextOurs : nextTheirs;
long green = (player.isBlue())? nextTheirs: nextOurs;
move = new Move(player, new Board(blue, green), true);
}
automover.relay(move);
}
}
}
concurrent-dfsg-1.3.4/taskDemo/Heat.java 0000644 0001750 0001750 00000017255 10202157355 020351 0 ustar wbaer wbaer 0000000 0000000 /*
Converted from heat.cilk, which is
Copyright (c) 1996 Massachusetts Institute of Technology
with the following notice:
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to use, copy, modify, and distribute the Software without
* restriction, provided the Software, including any modified copies made
* under this license, is not distributed for a fee, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE MASSACHUSETTS INSTITUTE OF TECHNOLOGY BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the name of the Massachusetts
* Institute of Technology shall not be used in advertising or otherwise
* to promote the sale, use or other dealings in this Software without
* prior written authorization from the Massachusetts Institute of
* Technology.
*
*/
import EDU.oswego.cs.dl.util.concurrent.*;
public class Heat {
// Parameters
static int nx;
static int ny;
static int nt;
static int leafmaxcol;
// the matrix representing the cells
static double[][] newm;
// alternating workspace matrix
static double[][] oldm;
public static void main(String[] args) {
int procs = 1;
int benchmark = 0;
try {
procs = Integer.parseInt(args[0]);
benchmark = Integer.parseInt(args[1]);
}
catch (Exception e) {
System.out.println("Usage: java Heat
These programs are intended to show interesting variations in
techniques, and do not necessarily demonstrate optimal performance.
But some of the programs have been adapted from other common demo
and benchmark programs used in parallel processing packages. To
make comparisons with them fairer, I've usually tried to keep
faithful to original quirks. (In fact a few were constructed by
taking original C code and mangling it until javac declared that it
was legal java code :-)
All of the programs are run by:
* This class was adapted from the SwingWorker written by Hans Muller
* and presented in "Using a Swing Worker Thread" in the Swing Connection
* - http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html
*
* A closely related version of this class is described in
* "The Last Word in Swing Threads" in the Swing Connection
* - http://java.sun.com/products/jfc/tsc/articles/threads/threads3.html
*
* This SwingWorker is a ThreadFactoryUser and implements Runnable. The
* default thread factory creates low-priority worker threads. A special
* constructor is provided for enabling a timeout. When the timeout
* expires, the worker thread is interrupted.
*
* Note: Using a timeout of
* Sample Usage
* [ Introduction to this package. ]
*/
public abstract class SwingWorker extends ThreadFactoryUser
implements Runnable {
/** Default thread factory. Creates low priority worker threads. */
private static final ThreadFactory FACTORY = new ThreadFactory() {
public Thread newThread(Runnable command) {
Thread t = new Thread(command);
t.setPriority(Thread.MIN_PRIORITY+1);
return t;
}
};
/** Holds the value to be returned by the
* IO Exceptions are transformed into Errors. This is
* in general not a good idea, but seems to be the most
* reasonable compromise for the intended usage contexts.
*
* Status Uncertain. There are enough
* conceptual and implementation snags surrounding use
* of pipes as Channels to downplay use. However,
* without such bridges, people would have to
* duplicate code that should work the same way in both cases.
*
* [ Introduction to this package. ]
**/
public class PipedChannel extends SemaphoreControlledChannel {
protected ObjectInputStream in_;
protected ObjectOutputStream out_;
protected final PipedOutputStream outp_;
protected final PipedInputStream inp_;
public PipedChannel() {
super(1);
try {
outp_ = new PipedOutputStream();
inp_ = new PipedInputStream();
inp_.connect(outp_);
}
catch (IOException ex) {
ex.printStackTrace();
throw new Error("Cannot construct Pipe?");
}
}
/**
* Return input stream, first constructing if necessary.
* Needed because Object streams can block on open.
**/
protected synchronized ObjectInputStream in() {
try {
if (in_ == null) in_ = new ObjectInputStream(inp_);
return in_;
}
catch (IOException ex) {
ex.printStackTrace();
throw new Error("IO exception during open");
}
}
/**
* Return output stream, first constructing if necessary.
* Needed because Object streams can block on open.
**/
protected synchronized ObjectOutputStream out() {
try {
if (out_ == null) out_ = new ObjectOutputStream(outp_);
return out_;
}
catch (IOException ex) {
ex.printStackTrace();
throw new Error("IO exception during open");
}
}
/** Shared mechanics for put-based methods **/
protected void insert(Object x) {
try {
out().writeObject(x);
}
catch (InterruptedIOException ex) {
Thread.currentThread().interrupt();
}
catch (IOException ex) {
ex.printStackTrace();
throw new Error("IO exception during put");
}
}
/** Shared mechanics for take-based methods **/
protected Object extract() {
try {
return in().readObject();
}
catch (InterruptedIOException ex) {
Thread.currentThread().interrupt();
return null;
}
catch (IOException ex) {
ex.printStackTrace();
throw new Error("IO exception during take");
}
catch (ClassNotFoundException ex) {
ex.printStackTrace();
throw new Error("Serialization exception during take");
}
}
/** Stubbed out for now **/
public Object peek() { return null; }
}
concurrent-dfsg-1.3.4/misc/SynchronizationTimer.java 0000644 0001750 0001750 00000177352 10202157355 023063 0 ustar wbaer wbaer 0000000 0000000 /*
File: SynchronizationTimer.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
7Jul1998 dl Create public version
16Jul1998 dl fix intialization error for compute loops
combined into one frame
misc layout and defaults changes
increase printed precision
overlap get/set in Executor tests
Swap defaults for swing import
Active thread counts reflect executors
30Aug1998 dl Misc revisions to mesh with 1.1.0
27jan1999 dl Eliminate GC calls
24Nov2001 dl Increase some default values
*/
package EDU.oswego.cs.dl.util.concurrent.misc;
// Swap the following sets of imports if necessary.
import javax.swing.*;
import javax.swing.border.*;
//import com.sun.java.swing.*;
//import com.sun.java.swing.border.*;
import EDU.oswego.cs.dl.util.concurrent.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.lang.reflect.*;
/**
*
* This program records times for various fine-grained synchronization
* schemes, and provides some ways of measuring them over different
* context parameters.
*
*
* Quick start:
*
* Synchronization schemes are tested around implementations and
* subclasses of
* Each iteration of each test ultimately somehow calls
* the random number generation
* method of an RNG. The time listed is the average time it took to do
* one iteration, in microseconds. These are just based on wallclock
* time (System.currentTimeMillis()). Thread
* construction time is NOT included in these times.
* In tests with many threads, construction and other bookkeeping
* can take longer than the tests themselves.
*
* Results are listed in a table, and optionally printed on standard output.
* You can redirect standard output to save to a file.
*
* The total amount of ``real'' computation reported in each cell is
* the same. Thus, the unobtainably ideal pattern of results would be
* for every cell of the table to be the same (and very small).
*
* A thread pool (PooledExecutor) is used to manage the threads used in
* test runs. The current number of active threads is indicated in
* the panel. It should normally be at most three plus the number of threads used in the
* indicated test column (there are at most three overhead threads per run), although
* it may transiently climb, and is larger in those tests that
* generate their own internal threads (for example ThreadedExceutor). If the
* indicated size fails to return to zero within about 10 seconds of
* either hitting stop
* or the end of a run, you may have a
* problem with interruption handling on your Java VM.
*
*
* This program cannot
* tell you how busy your computer is while running tests.
* You can run a utility program (for
* example
* A number of control parameters can be changed at any time.
* Most combinations of parameter settings create contexts
* that are completely unrepresentative of those seen in practical
* applications. However, they can be set to provide rough analogs of
* real applications, and the results used as rough guesses about
* performance impact. Also, do not be too upset about slow
* performance on tests representing situations
* that would never occur in practice.
*
*
* You can control parameters by clicking any of the following,
* at any time. (You can even change parameters
* while tests are running, in which case they will take
* effect as soon as possible. Most controls momentarily stall
* while test objects and threads are being constructed, to avoid
* inconsistencies during test runs.)
*
* To scaffold all this, the RNG class is defined in
* layers. Each RNG has internal non-public methods that do the actual
* computation, and public methods that call the internal ones. The
* particular classes run in tests might change over time, but
* currently includes the following general kinds:
*
*
*
* The test code is ugly; it has just evolved over the years. Sorry.
**/
public class SynchronizationTimer {
/** Start up this application **/
public static void main(String[] args) {
JFrame frame = new JFrame("Times per call in microseconds");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});
frame.getContentPane().add(new SynchronizationTimer().mainPanel());
frame.pack();
frame.setVisible(true);
}
/**
* Information about classes to be tested
**/
static class TestedClass {
final String name;
final Class cls;
final boolean multipleOK;
final boolean singleOK;
final Class buffCls;
Boolean enabled_ = new Boolean(true);
synchronized void setEnabled(Boolean b) { enabled_ = b; }
synchronized Boolean getEnabled() { return enabled_; }
synchronized void toggleEnabled() {
boolean enabled = enabled_.booleanValue();
enabled_ = new Boolean(!enabled);
}
synchronized boolean isEnabled(int nthreads, Fraction shared) {
boolean enabled = enabled_.booleanValue();
if (!enabled) return false;
if (!singleOK && nthreads <= 1) return false;
if (!multipleOK && nthreads > 1 && shared.compareTo(0) > 0) return false;
return true;
}
TestedClass(String n, Class c, boolean m, boolean sok) {
name = n; cls = c; multipleOK = m; singleOK = sok;
buffCls = null;
}
TestedClass(String n, Class c, boolean m, boolean sok, Class bc) {
name = n; cls = c; multipleOK = m; singleOK = sok;
buffCls = bc;
}
static final TestedClass dummy =
new TestedClass("", null, false, false);
static final TestedClass[] classes = {
new TestedClass("NoSynchronization", NoSynchRNG.class, false, true),
new TestedClass("PublicSynchronization", PublicSynchRNG.class, true, true),
new TestedClass("NestedSynchronization", AllSynchRNG.class, true, true),
new TestedClass("SDelegated", SDelegatedRNG.class, true, true),
new TestedClass("SynchLongUsingSet", SynchLongRNG.class, true, true),
new TestedClass("SynchLongUsingCommit", AClongRNG.class, true, true),
new TestedClass("Semaphore", SemRNG.class, true, true),
new TestedClass("WaiterPrefSemaphore", WpSemRNG.class, true, true),
new TestedClass("FIFOSemaphore", FifoRNG.class, true, true),
new TestedClass("PrioritySemaphore", PrioritySemRNG.class, true, true),
new TestedClass("Mutex", MutexRNG.class, true, true),
new TestedClass("ReentrantLock", RlockRNG.class, true, true),
new TestedClass("WriterPrefRWLock", WpRWlockRNG.class, true, true),
new TestedClass("ReaderPrefRWLock", ReaderPrefRWlockRNG.class, true, true),
new TestedClass("FIFORWLock", FIFORWlockRNG.class, true, true),
new TestedClass("ReentrantRWL", ReentrantRWlockRNG.class, true, true),
new TestedClass("LinkedQueue", ChanRNG.class, true, true,
LinkedQueue.class),
new TestedClass("WaitFreeQueue", ChanRNG.class, true, true,
WaitFreeQueue.class),
new TestedClass("BoundedLinkedQueue", ChanRNG.class, true, true,
BoundedLinkedQueue.class),
new TestedClass("BoundedBuffer", ChanRNG.class, true, true,
BoundedBuffer.class),
new TestedClass("CondVarBoundedBuffer", ChanRNG.class, true, true,
CVBuffer.class),
new TestedClass("BoundedPriorityQueue", ChanRNG.class, true, true,
BoundedPriorityQueue.class),
new TestedClass("Slot", ChanRNG.class, true, true,
Slot.class),
// new TestedClass("FIFOSlot", ChanRNG.class, true, true, FIFOSlot.class),
new TestedClass("SynchronousChannel", ChanRNG.class, true, false,
SynchronousChannel.class),
new TestedClass("DirectExecutor", DirectExecutorRNG.class, true, true),
new TestedClass("SemaphoreLckExecutor", LockedSemRNG.class, true, true),
new TestedClass("QueuedExecutor", QueuedExecutorRNG.class, true, true),
new TestedClass("ThreadedExecutor", ThreadedExecutorRNG.class, true, true),
new TestedClass("PooledExecutor", PooledExecutorRNG.class, true, true),
// new TestedClass("Pipe", ChanRNG.class, true, true, PipedChannel.class),
};
}
// test parameters
static final int[] nthreadsChoices = {
1,
2,
4,
8,
16,
32,
64,
128,
256,
512,
1024
};
static final int BLOCK_MODE = 0;
static final int TIMEOUT_MODE = 1;
static final int[] syncModes = { BLOCK_MODE, TIMEOUT_MODE, };
// misc formatting utilities
static String modeToString(int m) {
String sms;
if (m == BLOCK_MODE) sms = "block";
else if (m == TIMEOUT_MODE) sms = "timeout";
else sms = "No such mode";
return sms;
}
static String biasToString(int b) {
String sms;
if (b < 0) sms = "slower producer";
else if (b == 0) sms = "balanced prod/cons rate";
else if (b > 0) sms = "slower consumer";
else sms = "No such bias";
return sms;
}
static String p2ToString(int n) { // print power of two
String suf = "";
if (n >= 1024) {
n = n / 1024;
suf = "K";
if (n >= 1024) {
n = n / 1024;
suf = "M";
}
}
return n + suf;
}
static final int PRECISION = 10; // microseconds
static String formatTime(long ns, boolean showDecimal) {
long intpart = ns / PRECISION;
long decpart = ns % PRECISION;
if (!showDecimal) {
if (decpart >= PRECISION/2)
++intpart;
return Long.toString(intpart);
}
else {
String sint = Long.toString(intpart);
String sdec = Long.toString(decpart);
if (decpart == 0) {
int z = PRECISION;
while (z > 10) {
sdec = "0" + sdec;
z /= 10;
}
}
String ts = sint + "." + sdec;
return ts;
}
}
static class ThreadInfo {
final String name;
final int number;
Boolean enabled;
ThreadInfo(int nthr) {
number = nthr;
name = p2ToString(nthr);
enabled = new Boolean(true);
}
synchronized Boolean getEnabled() { return enabled; }
synchronized void setEnabled(Boolean v) { enabled = v; }
synchronized void toggleEnabled() {
enabled = new Boolean(!enabled.booleanValue());
}
}
final ThreadInfo[] threadInfo = new ThreadInfo[nthreadsChoices.length];
boolean threadEnabled(int nthreads) {
return threadInfo[nthreads].getEnabled().booleanValue();
}
// This used to be a JTable datamodel, but now just part of this class ...
final static int headerRows = 1;
final static int classColumn = 0;
final static int headerColumns = 1;
final int tableRows = TestedClass.classes.length + headerRows;
final int tableColumns = nthreadsChoices.length + headerColumns;
final JComponent[][] resultTable_ = new JComponent[tableRows][tableColumns];
JPanel resultPanel() {
JPanel[] colPanel = new JPanel[tableColumns];
for (int col = 0; col < tableColumns; ++col) {
colPanel[col] = new JPanel();
colPanel[col].setLayout(new GridLayout(tableRows, 1));
if (col != 0)
colPanel[col].setBackground(Color.white);
}
Color hdrbg = colPanel[0].getBackground();
Border border = new LineBorder(hdrbg);
Font font = new Font("Dialog", Font.PLAIN, 12);
Dimension labDim = new Dimension(40, 16);
Dimension cbDim = new Dimension(154, 16);
JLabel cornerLab = new JLabel(" Classes \\ Threads");
cornerLab.setMinimumSize(cbDim);
cornerLab.setPreferredSize(cbDim);
cornerLab.setFont(font);
resultTable_[0][0] = cornerLab;
colPanel[0].add(cornerLab);
for (int col = 1; col < tableColumns; ++col) {
final int nthreads = col - headerColumns;
JCheckBox tcb = new JCheckBox(threadInfo[nthreads].name, true);
tcb.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
threadInfo[nthreads].toggleEnabled();
}});
tcb.setMinimumSize(labDim);
tcb.setPreferredSize(labDim);
tcb.setFont(font);
tcb.setBackground(hdrbg);
resultTable_[0][col] = tcb;
colPanel[col].add(tcb);
}
for (int row = 1; row < tableRows; ++row) {
final int cls = row - headerRows;
JCheckBox cb = new JCheckBox(TestedClass.classes[cls].name, true);
cb.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
TestedClass.classes[cls].toggleEnabled();
}});
resultTable_[row][0] = cb;
cb.setMinimumSize(cbDim);
cb.setPreferredSize(cbDim);
cb.setFont(font);
colPanel[0].add(cb);
for (int col = 1; col < tableColumns; ++col) {
int nthreads = col - headerColumns;
JLabel lab = new JLabel("");
resultTable_[row][col] = lab;
lab.setMinimumSize(labDim);
lab.setPreferredSize(labDim);
lab.setBorder(border);
lab.setFont(font);
lab.setBackground(Color.white);
lab.setForeground(Color.black);
lab.setHorizontalAlignment(JLabel.RIGHT);
colPanel[col].add(lab);
}
}
JPanel tblPanel = new JPanel();
tblPanel.setLayout(new BoxLayout(tblPanel, BoxLayout.X_AXIS));
for (int col = 0; col < tableColumns; ++col) {
tblPanel.add(colPanel[col]);
}
return tblPanel;
}
void setTime(final long ns, int clsIdx, int nthrIdx) {
int row = clsIdx+headerRows;
int col = nthrIdx+headerColumns;
final JLabel cell = (JLabel)(resultTable_[row][col]);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
cell.setText(formatTime(ns, true));
}
});
}
void clearTable() {
for (int i = 1; i < tableRows; ++i) {
for (int j = 1; j < tableColumns; ++j) {
((JLabel)(resultTable_[i][j])).setText("");
}
}
}
void setChecks(final boolean setting) {
for (int i = 0; i < TestedClass.classes.length; ++i) {
TestedClass.classes[i].setEnabled(new Boolean(setting));
((JCheckBox)resultTable_[i+1][0]).setSelected(setting);
}
}
public SynchronizationTimer() {
for (int i = 0; i < threadInfo.length; ++i)
threadInfo[i] = new ThreadInfo(nthreadsChoices[i]);
}
final SynchronizedInt nextClassIdx_ = new SynchronizedInt(0);
final SynchronizedInt nextThreadIdx_ = new SynchronizedInt(0);
JPanel mainPanel() {
new PrintStart(); // classloader bug workaround
JPanel paramPanel = new JPanel();
paramPanel.setLayout(new GridLayout(5, 3));
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(1, 3));
startstop_.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (running_.get())
cancel();
else {
try {
startTestSeries(new TestSeries());
}
catch (InterruptedException ex) {
endTestSeries();
}
}
}});
paramPanel.add(startstop_);
JPanel p1 = new JPanel();
p1.setLayout(new GridLayout(1, 2));
JButton continueButton = new JButton("Continue");
continueButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if (!running_.get()) {
try {
startTestSeries(new TestSeries(nextClassIdx_.get(),
nextThreadIdx_.get()));
}
catch (InterruptedException ex) {
endTestSeries();
}
}
}});
p1.add(continueButton);
JButton clearButton = new JButton("Clear cells");
clearButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt) {
clearTable();
}
});
p1.add(clearButton);
paramPanel.add(p1);
JPanel p3 = new JPanel();
p3.setLayout(new GridLayout(1, 2));
JButton setButton = new JButton("All classes");
setButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt) {
setChecks(true);
}
});
p3.add(setButton);
JButton unsetButton = new JButton("No classes");
unsetButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt) {
setChecks(false);
}
});
p3.add(unsetButton);
paramPanel.add(p3);
JPanel p2 = new JPanel();
// p2.setLayout(new GridLayout(1, 2));
p2.setLayout(new BoxLayout(p2, BoxLayout.X_AXIS));
JCheckBox consoleBox = new JCheckBox("Console echo");
consoleBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
echoToSystemOut.complement();
}
});
JLabel poolinfo = new JLabel("Active threads: 0");
p2.add(poolinfo);
p2.add(consoleBox);
paramPanel.add(p2);
paramPanel.add(contentionBox());
paramPanel.add(itersBox());
paramPanel.add(cloopBox());
paramPanel.add(barrierBox());
paramPanel.add(exchangeBox());
paramPanel.add(biasBox());
paramPanel.add(capacityBox());
paramPanel.add(timeoutBox());
paramPanel.add(syncModePanel());
paramPanel.add(producerSyncModePanel());
paramPanel.add(consumerSyncModePanel());
startPoolStatus(poolinfo);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
JPanel tblPanel = resultPanel();
mainPanel.add(tblPanel);
mainPanel.add(paramPanel);
return mainPanel;
}
JComboBox syncModePanel() {
JComboBox syncModeComboBox = new JComboBox();
for (int j = 0; j < syncModes.length; ++j) {
String lab = "Locks: " + modeToString(syncModes[j]);
syncModeComboBox.addItem(lab);
}
syncModeComboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
JComboBox src = (JComboBox)(evt.getItemSelectable());
int idx = src.getSelectedIndex();
RNG.syncMode.set(syncModes[idx]);
}
});
RNG.syncMode.set(syncModes[0]);
syncModeComboBox.setSelectedIndex(0);
return syncModeComboBox;
}
JComboBox producerSyncModePanel() {
JComboBox producerSyncModeComboBox = new JComboBox();
for (int j = 0; j < syncModes.length; ++j) {
String lab = "Producers: " + modeToString(syncModes[j]);
producerSyncModeComboBox.addItem(lab);
}
producerSyncModeComboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
JComboBox src = (JComboBox)(evt.getItemSelectable());
int idx = src.getSelectedIndex();
RNG.producerMode.set(syncModes[idx]);
}
});
RNG.producerMode.set(syncModes[0]);
producerSyncModeComboBox.setSelectedIndex(0);
return producerSyncModeComboBox;
}
JComboBox consumerSyncModePanel() {
JComboBox consumerSyncModeComboBox = new JComboBox();
for (int j = 0; j < syncModes.length; ++j) {
String lab = "Consumers: " + modeToString(syncModes[j]);
consumerSyncModeComboBox.addItem(lab);
}
consumerSyncModeComboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
JComboBox src = (JComboBox)(evt.getItemSelectable());
int idx = src.getSelectedIndex();
RNG.consumerMode.set(syncModes[idx]);
}
});
RNG.consumerMode.set(syncModes[0]);
consumerSyncModeComboBox.setSelectedIndex(0);
return consumerSyncModeComboBox;
}
JComboBox contentionBox() {
final Fraction[] contentionChoices = {
new Fraction(0, 1),
new Fraction(1, 16),
new Fraction(1, 8),
new Fraction(1, 4),
new Fraction(1, 2),
new Fraction(1, 1)
};
JComboBox contentionComboBox = new JComboBox();
for (int j = 0; j < contentionChoices.length; ++j) {
String lab = contentionChoices[j].asDouble() * 100.0 +
"% contention/sharing";
contentionComboBox.addItem(lab);
}
contentionComboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
JComboBox src = (JComboBox)(evt.getItemSelectable());
int idx = src.getSelectedIndex();
contention_.set(contentionChoices[idx]);
}
});
contention_.set(contentionChoices[3]);
contentionComboBox.setSelectedIndex(3);
return contentionComboBox;
}
JComboBox itersBox() {
final int[] loopsPerTestChoices = {
1,
16,
256,
1024,
2 * 1024,
4 * 1024,
8 * 1024,
16 * 1024,
32 * 1024,
64 * 1024,
128 * 1024,
256 * 1024,
512 * 1024,
1024 * 1024,
};
JComboBox precComboBox = new JComboBox();
for (int j = 0; j < loopsPerTestChoices.length; ++j) {
String lab = p2ToString(loopsPerTestChoices[j]) +
" calls per thread per test";
precComboBox.addItem(lab);
}
precComboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
JComboBox src = (JComboBox)(evt.getItemSelectable());
int idx = src.getSelectedIndex();
loopsPerTest_.set(loopsPerTestChoices[idx]);
}
});
loopsPerTest_.set(loopsPerTestChoices[8]);
precComboBox.setSelectedIndex(8);
return precComboBox;
}
JComboBox cloopBox() {
final int[] computationsPerCallChoices = {
1,
2,
4,
8,
16,
32,
64,
128,
256,
512,
1024,
2 * 1024,
4 * 1024,
8 * 1024,
16 * 1024,
32 * 1024,
64 * 1024,
};
JComboBox cloopComboBox = new JComboBox();
for (int j = 0; j < computationsPerCallChoices.length; ++j) {
String lab = p2ToString(computationsPerCallChoices[j]) +
" computations per call";
cloopComboBox.addItem(lab);
}
cloopComboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
JComboBox src = (JComboBox)(evt.getItemSelectable());
int idx = src.getSelectedIndex();
RNG.computeLoops.set(computationsPerCallChoices[idx]);
}
});
RNG.computeLoops.set(computationsPerCallChoices[3]);
cloopComboBox.setSelectedIndex(3);
return cloopComboBox;
}
JComboBox barrierBox() {
final int[] itersPerBarrierChoices = {
1,
2,
4,
8,
16,
32,
64,
128,
256,
512,
1024,
2 * 1024,
4 * 1024,
8 * 1024,
16 * 1024,
32 * 1024,
64 * 1024,
128 * 1024,
256 * 1024,
512 * 1024,
1024 * 1024,
};
JComboBox barrierComboBox = new JComboBox();
for (int j = 0; j < itersPerBarrierChoices.length; ++j) {
String lab = p2ToString(itersPerBarrierChoices[j]) +
" iterations per barrier";
barrierComboBox.addItem(lab);
}
barrierComboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
JComboBox src = (JComboBox)(evt.getItemSelectable());
int idx = src.getSelectedIndex();
RNG.itersPerBarrier.set(itersPerBarrierChoices[idx]);
}
});
RNG.itersPerBarrier.set(itersPerBarrierChoices[13]);
barrierComboBox.setSelectedIndex(13);
// RNG.itersPerBarrier.set(itersPerBarrierChoices[15]);
// barrierComboBox.setSelectedIndex(15);
return barrierComboBox;
}
JComboBox exchangeBox() {
final int[] exchangerChoices = {
1,
2,
4,
8,
16,
32,
64,
128,
256,
512,
1024,
};
JComboBox exchComboBox = new JComboBox();
for (int j = 0; j < exchangerChoices.length; ++j) {
String lab = p2ToString(exchangerChoices[j]) +
" max threads per barrier";
exchComboBox.addItem(lab);
}
exchComboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
JComboBox src = (JComboBox)(evt.getItemSelectable());
int idx = src.getSelectedIndex();
RNG.exchangeParties.set(exchangerChoices[idx]);
}
});
RNG.exchangeParties.set(exchangerChoices[1]);
exchComboBox.setSelectedIndex(1);
return exchComboBox;
}
JComboBox biasBox() {
final int[] biasChoices = {
-1,
0,
1
};
JComboBox biasComboBox = new JComboBox();
for (int j = 0; j < biasChoices.length; ++j) {
String lab = biasToString(biasChoices[j]);
biasComboBox.addItem(lab);
}
biasComboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
JComboBox src = (JComboBox)(evt.getItemSelectable());
int idx = src.getSelectedIndex();
RNG.bias.set(biasChoices[idx]);
}
});
RNG.bias.set(biasChoices[1]);
biasComboBox.setSelectedIndex(1);
return biasComboBox;
}
JComboBox capacityBox() {
final int[] bufferCapacityChoices = {
1,
4,
64,
256,
1024,
4096,
16 * 1024,
64 * 1024,
256 * 1024,
1024 * 1024,
};
JComboBox bcapComboBox = new JComboBox();
for (int j = 0; j < bufferCapacityChoices.length; ++j) {
String lab = p2ToString(bufferCapacityChoices[j]) +
" element bounded buffers";
bcapComboBox.addItem(lab);
}
bcapComboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
JComboBox src = (JComboBox)(evt.getItemSelectable());
int idx = src.getSelectedIndex();
DefaultChannelCapacity.set(bufferCapacityChoices[idx]);
}
});
DefaultChannelCapacity.set(bufferCapacityChoices[3]);
bcapComboBox.setSelectedIndex(3);
return bcapComboBox;
}
JComboBox timeoutBox() {
final long[] timeoutChoices = {
0,
1,
10,
100,
1000,
10000,
100000,
};
JComboBox timeoutComboBox = new JComboBox();
for (int j = 0; j < timeoutChoices.length; ++j) {
String lab = timeoutChoices[j] + " msec timeouts";
timeoutComboBox.addItem(lab);
}
timeoutComboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent evt) {
JComboBox src = (JComboBox)(evt.getItemSelectable());
int idx = src.getSelectedIndex();
RNG.timeout.set(timeoutChoices[idx]);
}
});
RNG.timeout.set(timeoutChoices[3]);
timeoutComboBox.setSelectedIndex(3);
return timeoutComboBox;
}
ClockDaemon timeDaemon = new ClockDaemon();
void startPoolStatus(final JLabel status) {
Runnable updater = new Runnable() {
int lastps = 0;
public void run() {
final int ps = Threads.activeThreads.get();
if (lastps != ps) {
lastps = ps;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
status.setText("Active threads: " + ps);
} } );
}
}
};
timeDaemon.executePeriodically(250, updater, false);
}
private final SynchronizedRef contention_ = new SynchronizedRef(null);
private final SynchronizedInt loopsPerTest_ = new SynchronizedInt(0);
private final SynchronizedBoolean echoToSystemOut =
new SynchronizedBoolean(false);
private final JButton startstop_ = new JButton("Start");
private WaitableInt testNumber_ = new WaitableInt(1);
private void runOneTest(Runnable tst) throws InterruptedException {
int nt = testNumber_.get();
Threads.pool.execute(tst);
testNumber_.whenNotEqual(nt, null);
}
private void endOneTest() {
testNumber_.increment();
}
private SynchronizedBoolean running_ = new SynchronizedBoolean(false);
void cancel() {
// not stable enough to cancel during construction
synchronized (RNG.constructionLock) {
try {
Threads.pool.interruptAll();
}
catch(Exception ex) {
System.out.println("\nException during cancel:\n" + ex);
return;
}
}
}
void startTestSeries(Runnable tst) throws InterruptedException {
running_.set(true);
startstop_.setText("Stop");
Threads.pool.execute(tst);
}
// prevent odd class-gc problems on some VMs?
class PrintStart implements Runnable {
public void run() {
startstop_.setText("Start");
}
}
void endTestSeries() {
running_.set(false);
SwingUtilities.invokeLater(new PrintStart());
}
/*
void old_endTestSeries() {
running_.set(false);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
startstop_.setText("Start");
} } );
}
*/
class TestSeries implements Runnable {
final int firstclass;
final int firstnthreads;
TestSeries() {
firstclass = 0;
firstnthreads = 0;
}
TestSeries(final int firstc, final int firstnt) {
firstclass = firstc;
firstnthreads = firstnt;
}
public void run() {
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
try {
int t = firstnthreads;
int c = firstclass;
if (t < nthreadsChoices.length &&
c < TestedClass.classes.length) {
for (;;) {
// these checks are duplicated in OneTest, but added here
// to minimize unecessary thread construction,
// which can skew results
if (threadEnabled(t)) {
TestedClass entry = TestedClass.classes[c];
int nthreads = nthreadsChoices[t];
int iters = loopsPerTest_.get();
Fraction pshr = (Fraction)(contention_.get());
if (entry.isEnabled(nthreads, pshr)) {
runOneTest(new OneTest(c, t));
}
}
if (++c >= TestedClass.classes.length) {
c = 0;
if (++t >= nthreadsChoices.length)
break;
}
nextClassIdx_.set(c);
nextThreadIdx_.set(t);
}
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
finally {
endTestSeries();
}
}
}
static class BarrierTimer implements Runnable {
private long startTime_ = 0;
private long endTime_ = 0;
public synchronized long getTime() {
return endTime_ - startTime_;
}
public synchronized void run() {
long now = System.currentTimeMillis();
if (startTime_ == 0)
startTime_ = now;
else
endTime_ = now;
}
}
class OneTest implements Runnable {
final int clsIdx;
final int nthreadsIdx;
OneTest(int idx, int t) {
clsIdx = idx;
nthreadsIdx = t;
}
public void run() {
Thread.currentThread().setPriority(Thread.NORM_PRIORITY-3);
boolean wasInterrupted = false;
final TestedClass entry = TestedClass.classes[clsIdx];
final JLabel cell = (JLabel)(resultTable_[clsIdx+1][nthreadsIdx+1]);
final Color oldfg = cell.getForeground();
try {
if (Thread.interrupted()) return;
if (!threadEnabled(nthreadsIdx)) return;
int nthreads = nthreadsChoices[nthreadsIdx];
int iters = loopsPerTest_.get();
Fraction pshr = (Fraction)(contention_.get());
if (!entry.isEnabled(nthreads, pshr)) return;
BarrierTimer timer = new BarrierTimer();
CyclicBarrier barrier = new CyclicBarrier(nthreads+1, timer);
Class cls = entry.cls;
Class chanCls = entry.buffCls;
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
cell.setForeground(Color.blue);
cell.setText("RUN");
cell.repaint();
}
});
}
catch (InvocationTargetException ex) {
ex.printStackTrace();
System.exit(-1);
}
synchronized (RNG.constructionLock) {
RNG.reset(nthreads);
if (chanCls == null) {
RNG shared = (RNG)(cls.newInstance());
for (int k = 0; k < nthreads; ++k) {
RNG pri = (RNG)(cls.newInstance());
TestLoop l = new TestLoop(shared, pri, pshr, iters, barrier);
Threads.pool.execute(l.testLoop());
}
}
else {
Channel shared = (Channel)(chanCls.newInstance());
if (nthreads == 1) {
ChanRNG single = (ChanRNG)(cls.newInstance());
single.setSingle(true);
PCTestLoop l = new PCTestLoop(single.getDelegate(), single, pshr,
iters, barrier,
shared, shared);
Threads.pool.execute(l.testLoop(true));
}
else if (nthreads % 2 != 0)
throw new Error("Must have even number of threads!");
else {
int npairs = nthreads / 2;
for (int k = 0; k < npairs; ++k) {
ChanRNG t = (ChanRNG)(cls.newInstance());
t.setSingle(false);
Channel chan = (Channel)(chanCls.newInstance());
PCTestLoop l = new PCTestLoop(t.getDelegate(), t, pshr,
iters, barrier,
shared, chan);
Threads.pool.execute(l.testLoop(false));
Threads.pool.execute(l.testLoop(true));
}
}
}
if (echoToSystemOut.get()) {
System.out.print(
entry.name + " " +
nthreads + "T " +
pshr + "S " +
RNG.computeLoops.get() + "I " +
RNG.syncMode.get() + "Lm " +
RNG.timeout.get() + "TO " +
RNG.producerMode.get() + "Pm " +
RNG.consumerMode.get() + "Cm " +
RNG.bias.get() + "B " +
DefaultChannelCapacity.get() + "C " +
RNG.exchangeParties.get() + "Xp " +
RNG.itersPerBarrier.get() + "Ib : "
);
}
}
// Uncomment if AWT doesn't update right
// Thread.sleep(100);
barrier.barrier(); // start
barrier.barrier(); // stop
long tm = timer.getTime();
long totalIters = nthreads * iters;
double dns = tm * 1000.0 * PRECISION / totalIters;
long ns = Math.round(dns);
setTime(ns, clsIdx, nthreadsIdx);
if (echoToSystemOut.get()) {
System.out.println(formatTime(ns, true));
}
}
catch (BrokenBarrierException ex) {
wasInterrupted = true;
}
catch (InterruptedException ex) {
wasInterrupted = true;
Thread.currentThread().interrupt();
}
catch (Exception ex) {
ex.printStackTrace();
System.out.println("Construction Exception?");
System.exit(-1);
}
finally {
final boolean clear = wasInterrupted;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (clear) cell.setText("");
cell.setForeground(oldfg);
cell.repaint();
}
});
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
endOneTest();
}
}
}
}
class Threads implements ThreadFactory {
static final SynchronizedInt activeThreads = new SynchronizedInt(0);
static final Threads factory = new Threads();
static final PooledExecutor pool = new PooledExecutor();
static {
pool.setKeepAliveTime(10000);
pool.setThreadFactory(factory);
}
static class MyThread extends Thread {
public MyThread(Runnable cmd) {
super(cmd);
}
public void run() {
activeThreads.increment();
try {
super.run();
}
finally {
activeThreads.decrement();
}
}
}
public Thread newThread(Runnable cmd) {
return new MyThread(cmd);
}
}
class TestLoop {
final RNG shared;
final RNG primary;
final int iters;
final Fraction pshared;
final CyclicBarrier barrier;
final boolean[] useShared;
final int firstidx;
public TestLoop(RNG sh, RNG pri, Fraction pshr, int it, CyclicBarrier br) {
shared = sh;
primary = pri;
pshared = pshr;
iters = it;
barrier = br;
firstidx = (int)(primary.get());
int num = (int)(pshared.numerator());
int denom = (int)(pshared.denominator());
if (num == 0 || primary == shared) {
useShared = new boolean[1];
useShared[0] = false;
}
else if (num >= denom) {
useShared = new boolean[1];
useShared[0] = true;
}
else {
// create bool array and randomize it.
// This ensures that always same number of shared calls.
// denom slots is too few. iters is too many. an arbitrary compromise is:
int xfactor = 1024 / denom;
if (xfactor < 1) xfactor = 1;
useShared = new boolean[denom * xfactor];
for (int i = 0; i < num * xfactor; ++i)
useShared[i] = true;
for (int i = num * xfactor; i < denom * xfactor; ++i)
useShared[i] = false;
for (int i = 1; i < useShared.length; ++i) {
int j = ((int) (shared.next() & 0x7FFFFFFF)) % (i + 1);
boolean tmp = useShared[i];
useShared[i] = useShared[j];
useShared[j] = tmp;
}
}
}
public Runnable testLoop() {
return new Runnable() {
public void run() {
int itersPerBarrier = RNG.itersPerBarrier.get();
try {
int delta = -1;
if (primary.getClass().equals(PrioritySemRNG.class)) {
delta = 2 - (int)((primary.get() % 5));
}
Thread.currentThread().setPriority(Thread.NORM_PRIORITY+delta);
int nshared = (int)(iters * pshared.asDouble());
int nprimary = iters - nshared;
int idx = firstidx;
barrier.barrier();
for (int i = iters; i > 0; --i) {
++idx;
if (i % itersPerBarrier == 0)
primary.exchange();
else {
RNG r;
if (nshared > 0 && useShared[idx % useShared.length]) {
--nshared;
r = shared;
}
else {
--nprimary;
r = primary;
}
long rnd = r.next();
if (rnd % 2 == 0 && Thread.currentThread().isInterrupted())
break;
}
}
}
catch (BrokenBarrierException ex) {
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
finally {
try {
barrier.barrier();
}
catch (BrokenBarrierException ex) {
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
finally {
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
}
}
}
};
}
}
class PCTestLoop extends TestLoop {
final Channel primaryChannel;
final Channel sharedChannel;
public PCTestLoop(RNG sh, RNG pri, Fraction pshr, int it,
CyclicBarrier br, Channel shChan, Channel priChan) {
super(sh, pri, pshr, it, br);
sharedChannel = shChan;
primaryChannel = priChan;
}
public Runnable testLoop(final boolean isProducer) {
return new Runnable() {
public void run() {
int delta = -1;
Thread.currentThread().setPriority(Thread.NORM_PRIORITY+delta);
int itersPerBarrier = RNG.itersPerBarrier.get();
try {
int nshared = (int)(iters * pshared.asDouble());
int nprimary = iters - nshared;
int idx = firstidx;
barrier.barrier();
ChanRNG target = (ChanRNG)(primary);
for (int i = iters; i > 0; --i) {
++idx;
if (i % itersPerBarrier == 0)
primary.exchange();
else {
Channel c;
if (nshared > 0 && useShared[idx % useShared.length]) {
--nshared;
c = sharedChannel;
}
else {
--nprimary;
c = primaryChannel;
}
long rnd;
if (isProducer)
rnd = target.producerNext(c);
else
rnd = target.consumerNext(c);
if (rnd % 2 == 0 && Thread.currentThread().isInterrupted())
break;
}
}
}
catch (BrokenBarrierException ex) {
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
finally {
try {
barrier.barrier();
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
catch (BrokenBarrierException ex) {
}
finally {
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
}
}
}
};
}
}
// -------------------------------------------------------------
abstract class RNG implements Serializable, Comparable {
static final int firstSeed = 4321;
static final int rmod = 2147483647;
static final int rmul = 16807;
static int lastSeed = firstSeed;
static final int smod = 32749;
static final int smul = 3125;
static final Object constructionLock = RNG.class;
// Use construction lock for all params to disable
// changes in midst of construction of test objects.
static final SynchronizedInt computeLoops =
new SynchronizedInt(16, constructionLock);
static final SynchronizedInt syncMode =
new SynchronizedInt(0, constructionLock);
static final SynchronizedInt producerMode =
new SynchronizedInt(0, constructionLock);
static final SynchronizedInt consumerMode =
new SynchronizedInt(0, constructionLock);
static final SynchronizedInt bias =
new SynchronizedInt(0, constructionLock);
static final SynchronizedLong timeout =
new SynchronizedLong(100, constructionLock);
static final SynchronizedInt exchangeParties =
new SynchronizedInt(1, constructionLock);
static final SynchronizedInt sequenceNumber =
new SynchronizedInt(0, constructionLock);
static final SynchronizedInt itersPerBarrier =
new SynchronizedInt(0, constructionLock);
static Rendezvous[] exchangers_;
static void reset(int nthreads) {
synchronized(constructionLock) {
sequenceNumber.set(-1);
int parties = exchangeParties.get();
if (nthreads < parties) parties = nthreads;
if (nthreads % parties != 0)
throw new Error("need even multiple of parties");
exchangers_ = new Rendezvous[nthreads / parties];
for (int i = 0; i < exchangers_.length; ++i) {
exchangers_[i] = new Rendezvous(parties);
}
}
}
static long nextSeed() {
synchronized(constructionLock) {
long s = lastSeed;
lastSeed = (lastSeed * smul) % smod;
if (lastSeed == 0)
lastSeed = (int)(System.currentTimeMillis());
return s;
}
}
final int cloops = computeLoops.get();
final int pcBias = bias.get();
final int smode = syncMode.get();
final int pmode = producerMode.get();
final int cmode = consumerMode.get();
final long waitTime = timeout.get();
Rendezvous exchanger_ = null;
synchronized Rendezvous getExchanger() {
if (exchanger_ == null) {
synchronized (constructionLock) {
int idx = sequenceNumber.increment();
exchanger_ = exchangers_[idx % exchangers_.length];
}
}
return exchanger_;
}
public void exchange() throws InterruptedException {
Rendezvous ex = getExchanger();
Runnable r = (Runnable)(ex.rendezvous(new UpdateCommand(this)));
if (r != null) r.run();
}
public int compareTo(Object other) {
int h1 = hashCode();
int h2 = other.hashCode();
if (h1 < h2) return -1;
else if (h1 > h2) return 1;
else return 0;
}
protected final long compute(long l) {
int loops = (int)((l & 0x7FFFFFFF) % (cloops * 2)) + 1;
for (int i = 0; i < loops; ++i) l = (l * rmul) % rmod;
return (l == 0)? firstSeed : l;
}
abstract protected void set(long l);
abstract protected long internalGet();
abstract protected void internalUpdate();
public long get() { return internalGet(); }
public void update() { internalUpdate(); }
public long next() { internalUpdate(); return internalGet(); }
}
class UpdateCommand implements Runnable, Serializable, Comparable {
private final RNG obj_;
final long cmpVal;
public UpdateCommand(RNG o) {
obj_ = o;
cmpVal = o.get();
}
public void run() { obj_.update(); }
public int compareTo(Object x) {
UpdateCommand u = (UpdateCommand)x;
if (cmpVal < u.cmpVal) return -1;
else if (cmpVal > u.cmpVal) return 1;
else return 0;
}
}
class GetFunction implements Callable {
private final RNG obj_;
public GetFunction(RNG o) { obj_ = o; }
public Object call() { return new Long(obj_.get()); }
}
class NextFunction implements Callable {
private final RNG obj_;
public NextFunction(RNG o) { obj_ = o; }
public Object call() { return new Long(obj_.next()); }
}
class NoSynchRNG extends RNG {
protected long current_ = nextSeed();
protected void set(long l) { current_ = l; }
protected long internalGet() { return current_; }
protected void internalUpdate() { set(compute(internalGet())); }
}
class PublicSynchRNG extends NoSynchRNG {
public synchronized long get() { return internalGet(); }
public synchronized void update() { internalUpdate(); }
public synchronized long next() { internalUpdate(); return internalGet(); }
}
class AllSynchRNG extends PublicSynchRNG {
protected synchronized void set(long l) { current_ = l; }
protected synchronized long internalGet() { return current_; }
protected synchronized void internalUpdate() { set(compute(internalGet())); }
}
class AClongRNG extends RNG {
protected final SynchronizedLong acurrent_ =
new SynchronizedLong(nextSeed());
protected void set(long l) { throw new Error("No set allowed"); }
protected long internalGet() { return acurrent_.get(); }
protected void internalUpdate() {
int retriesBeforeSleep = 100;
int maxSleepTime = 100;
int retries = 0;
for (;;) {
long v = internalGet();
long n = compute(v);
if (acurrent_.commit(v, n))
return;
else if (++retries >= retriesBeforeSleep) {
try {
Thread.sleep(n % maxSleepTime);
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
retries = 0;
}
}
}
}
class SynchLongRNG extends RNG {
protected final SynchronizedLong acurrent_ =
new SynchronizedLong(nextSeed());
protected void set(long l) { acurrent_.set(l); }
protected long internalGet() { return acurrent_.get(); }
protected void internalUpdate() { set(compute(internalGet())); }
}
abstract class DelegatedRNG extends RNG {
protected RNG delegate_ = null;
public synchronized void setDelegate(RNG d) { delegate_ = d; }
protected synchronized RNG getDelegate() { return delegate_; }
public long get() { return getDelegate().get(); }
public void update() { getDelegate().update(); }
public long next() { return getDelegate().next(); }
protected void set(long l) { throw new Error(); }
protected long internalGet() { throw new Error(); }
protected void internalUpdate() { throw new Error(); }
}
class SDelegatedRNG extends DelegatedRNG {
public SDelegatedRNG() { setDelegate(new NoSynchRNG()); }
public synchronized long get() { return getDelegate().get(); }
public synchronized void update() { getDelegate().update(); }
public synchronized long next() { return getDelegate().next(); }
}
class SyncDelegatedRNG extends DelegatedRNG {
protected final Sync cond_;
public SyncDelegatedRNG(Sync c) {
cond_ = c;
setDelegate(new NoSynchRNG());
}
protected final void acquire() throws InterruptedException {
if (smode == 0) {
cond_.acquire();
}
else {
while (!cond_.attempt(waitTime)) {}
}
}
public long next() {
try {
acquire();
getDelegate().update();
long l = getDelegate().get();
cond_.release();
return l;
}
catch(InterruptedException x) {
Thread.currentThread().interrupt();
return 0;
}
}
public long get() {
try {
acquire();
long l = getDelegate().get();
cond_.release();
return l;
}
catch(InterruptedException x) {
Thread.currentThread().interrupt();
return 0;
}
}
public void update() {
try {
acquire();
getDelegate().update();
cond_.release();
}
catch(InterruptedException x) {
Thread.currentThread().interrupt();
}
}
}
class MutexRNG extends SyncDelegatedRNG {
public MutexRNG() { super(new Mutex()); }
}
class SemRNG extends SyncDelegatedRNG {
public SemRNG() { super(new Semaphore(1)); }
}
class WpSemRNG extends SyncDelegatedRNG {
public WpSemRNG() { super(new WaiterPreferenceSemaphore(1)); }
}
class FifoRNG extends SyncDelegatedRNG {
public FifoRNG() { super(new FIFOSemaphore(1)); }
}
class PrioritySemRNG extends SyncDelegatedRNG {
public PrioritySemRNG() { super(new PrioritySemaphore(1)); }
}
class RlockRNG extends SyncDelegatedRNG {
public RlockRNG() { super(new ReentrantLock()); }
}
class RWLockRNG extends NoSynchRNG {
protected final ReadWriteLock lock_;
public RWLockRNG(ReadWriteLock l) {
lock_ = l;
}
protected final void acquireR() throws InterruptedException {
if (smode == 0) {
lock_.readLock().acquire();
}
else {
while (!lock_.readLock().attempt(waitTime)) {}
}
}
protected final void acquireW() throws InterruptedException {
if (smode == 0) {
lock_.writeLock().acquire();
}
else {
while (!lock_.writeLock().attempt(waitTime)) {}
}
}
public long next() {
long l = 0;
try {
acquireR();
l = current_;
lock_.readLock().release();
}
catch(InterruptedException x) {
Thread.currentThread().interrupt();
return 0;
}
l = compute(l);
try {
acquireW();
set(l);
lock_.writeLock().release();
return l;
}
catch(InterruptedException x) {
Thread.currentThread().interrupt();
return 0;
}
}
public long get() {
try {
acquireR();
long l = current_;
lock_.readLock().release();
return l;
}
catch(InterruptedException x) {
Thread.currentThread().interrupt();
return 0;
}
}
public void update() {
long l = 0;
try {
acquireR();
l = current_;
lock_.readLock().release();
}
catch(InterruptedException x) {
Thread.currentThread().interrupt();
return;
}
l = compute(l);
try {
acquireW();
set(l);
lock_.writeLock().release();
}
catch(InterruptedException x) {
Thread.currentThread().interrupt();
}
}
}
class WpRWlockRNG extends RWLockRNG {
public WpRWlockRNG() { super(new WriterPreferenceReadWriteLock()); }
}
class ReaderPrefRWlockRNG extends RWLockRNG {
public ReaderPrefRWlockRNG() {
super(new ReaderPreferenceReadWriteLock());
}
}
class FIFORWlockRNG extends RWLockRNG {
public FIFORWlockRNG() { super(new FIFOReadWriteLock()); }
}
class ReentrantRWlockRNG extends RWLockRNG {
public ReentrantRWlockRNG() {
super(new ReentrantWriterPreferenceReadWriteLock());
}
public void update() { // use embedded acquires
long l = 0;
try {
acquireW();
try {
acquireR();
l = current_;
lock_.readLock().release();
}
catch(InterruptedException x) {
Thread.currentThread().interrupt();
return;
}
l = compute(l);
set(l);
lock_.writeLock().release();
}
catch(InterruptedException x) {
Thread.currentThread().interrupt();
}
}
}
abstract class ExecutorRNG extends DelegatedRNG {
Executor executor_;
synchronized void setExecutor(Executor e) { executor_ = e; }
synchronized Executor getExecutor() { return executor_; }
Runnable delegatedUpdate_ = null;
Callable delegatedNext_ = null;
synchronized Runnable delegatedUpdateCommand() {
if (delegatedUpdate_ == null)
delegatedUpdate_ = new UpdateCommand(getDelegate());
return delegatedUpdate_;
}
synchronized Callable delegatedNextFunction() {
if (delegatedNext_ == null)
delegatedNext_ = new NextFunction(getDelegate());
return delegatedNext_;
}
public void update() {
try {
getExecutor().execute(delegatedUpdateCommand());
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
// Each call to next gets result of previous future
FutureResult nextResult_ = null;
public synchronized long next() {
long res = 0;
try {
if (nextResult_ == null) { // direct call first time through
nextResult_ = new FutureResult();
nextResult_.set(new Long(getDelegate().next()));
}
FutureResult currentResult = nextResult_;
nextResult_ = new FutureResult();
Runnable r = nextResult_.setter(delegatedNextFunction());
getExecutor().execute(r);
res = ((Long)(currentResult.get())).longValue();
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
catch (InvocationTargetException ex) {
ex.printStackTrace();
throw new Error("Bad Callable?");
}
return res;
}
}
class DirectExecutorRNG extends ExecutorRNG {
public DirectExecutorRNG() {
setDelegate(new PublicSynchRNG());
setExecutor(new DirectExecutor());
}
}
class LockedSemRNG extends ExecutorRNG {
public LockedSemRNG() {
setDelegate(new NoSynchRNG());
setExecutor(new LockedExecutor(new Semaphore(1)));
}
}
class QueuedExecutorRNG extends ExecutorRNG {
static final QueuedExecutor exec = new QueuedExecutor();
static { exec.setThreadFactory(Threads.factory); }
public QueuedExecutorRNG() {
setDelegate(new PublicSynchRNG());
setExecutor(exec);
}
}
class ForcedStartRunnable implements Runnable {
protected final Latch latch_ = new Latch();
protected final Runnable command_;
ForcedStartRunnable(Runnable command) { command_ = command; }
public Latch started() { return latch_; }
public void run() {
latch_.release();
command_.run();
}
}
class ForcedStartThreadedExecutor extends ThreadedExecutor {
public void execute(Runnable command) throws InterruptedException {
ForcedStartRunnable wrapped = new ForcedStartRunnable(command);
super.execute(wrapped);
wrapped.started().acquire();
}
}
class ThreadedExecutorRNG extends ExecutorRNG {
static final ThreadedExecutor exec = new ThreadedExecutor();
static { exec.setThreadFactory(Threads.factory); }
public ThreadedExecutorRNG() {
setDelegate(new PublicSynchRNG());
setExecutor(exec);
}
}
class PooledExecutorRNG extends ExecutorRNG {
static final PooledExecutor exec = Threads.pool;
public PooledExecutorRNG() {
setDelegate(new PublicSynchRNG());
setExecutor(exec);
}
}
class ChanRNG extends DelegatedRNG {
boolean single_;
ChanRNG() {
setDelegate(new PublicSynchRNG());
}
public synchronized void setSingle(boolean s) { single_ = s; }
public synchronized boolean isSingle() { return single_; }
public long producerNext(Channel c) throws InterruptedException {
RNG r = getDelegate();
if (isSingle()) {
c.put(r);
r = (RNG)(c.take());
r.update();
}
else {
if (pcBias < 0) {
r.update();
r.update(); // update consumer side too
}
else if (pcBias == 0) {
r.update();
}
if (pmode == 0) {
c.put(r);
}
else {
while (!(c.offer(r, waitTime))) {}
}
}
return r.get();
}
public long consumerNext(Channel c) throws InterruptedException {
RNG r = null;
if (cmode == 0) {
r = (RNG)(c.take());
}
else {
while (r == null) r = (RNG)(c.poll(waitTime));
}
if (pcBias == 0) {
r.update();
}
else if (pcBias > 0) {
r.update();
r.update();
}
return r.get();
}
}
concurrent-dfsg-1.3.4/build.xml 0000644 0001750 0001750 00000003343 10202637333 016667 0 ustar wbaer wbaer 0000000 0000000
[ Introduction to this package. ]
**/
public class LockedExecutor implements Executor {
/** The mutex **/
protected final Sync mutex_;
/**
* Create a new LockedExecutor that relies on the given mutual
* exclusion lock.
* @param mutex Any mutual exclusion lock.
* Standard usage is to supply an instance of
* CyclicBarriers use an all-or-none breakage model
* for failed synchronization attempts: If threads
* leave a barrier point prematurely because of timeout
* or interruption, others will also leave abnormally
* (via BrokenBarrierException), until
* the barrier is
* Barriers support an optional Runnable command
* that is run once per barrier point.
*
* Sample usage Here is a code sketch of
* a barrier in a parallel decomposition design.
* [ Introduction to this package. ]
**/
public class CyclicBarrier implements Barrier {
protected final int parties_;
protected boolean broken_ = false;
protected Runnable barrierCommand_ = null;
protected int count_; // number of parties still waiting
protected int resets_ = 0; // incremented on each release
/**
* Create a CyclicBarrier for the indicated number of parties,
* and no command to run at each barrier.
* @exception IllegalArgumentException if parties less than or equal to zero.
**/
public CyclicBarrier(int parties) { this(parties, null); }
/**
* Create a CyclicBarrier for the indicated number of parties.
* and the given command to run at each barrier point.
* @exception IllegalArgumentException if parties less than or equal to zero.
**/
public CyclicBarrier(int parties, Runnable command) {
if (parties <= 0) throw new IllegalArgumentException();
parties_ = parties;
count_ = parties;
barrierCommand_ = command;
}
/**
* Set the command to run at the point at which all threads reach the
* barrier. This command is run exactly once, by the thread
* that trips the barrier. The command is not run if the barrier is
* broken.
* @param command the command to run. If null, no command is run.
* @return the previous command
**/
public synchronized Runnable setBarrierCommand(Runnable command) {
Runnable old = barrierCommand_;
barrierCommand_ = command;
return old;
}
public synchronized boolean broken() { return broken_; }
/**
* Reset to initial state. Clears both the broken status
* and any record of waiting threads, and releases all
* currently waiting threads with indeterminate return status.
* This method is intended only for use in recovery actions
* in which it is somehow known
* that no thread could possibly be relying on the
* the synchronization properties of this barrier.
**/
public synchronized void restart() {
broken_ = false;
++resets_;
count_ = parties_;
notifyAll();
}
public int parties() { return parties_; }
/**
* Enter barrier and wait for the other parties()-1 threads.
* @return the arrival index: the number of other parties
* that were still waiting
* upon entry. This is a unique value from zero to parties()-1.
* If it is zero, then the current
* thread was the last party to hit barrier point
* and so was responsible for releasing the others.
* @exception BrokenBarrierException if any other thread
* in any previous or current barrier
* since either creation or the last [ Introduction to this package. ]
**/
public final class WaiterPreferenceSemaphore extends Semaphore {
/**
* Create a Semaphore with the given initial number of permits.
**/
public WaiterPreferenceSemaphore(long initial) { super(initial); }
/** Number of waiting threads **/
protected long waits_ = 0;
public void acquire() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
synchronized(this) {
/*
Only take if there are more permits than threads waiting
for permits. This prevents infinite overtaking.
*/
if (permits_ > waits_) {
--permits_;
return;
}
else {
++waits_;
try {
for (;;) {
wait();
if (permits_ > 0) {
--waits_;
--permits_;
return;
}
}
}
catch(InterruptedException ex) {
--waits_;
notify();
throw ex;
}
}
}
}
public boolean attempt(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
synchronized(this) {
if (permits_ > waits_) {
--permits_;
return true;
}
else if (msecs <= 0)
return false;
else {
++waits_;
long startTime = System.currentTimeMillis();
long waitTime = msecs;
try {
for (;;) {
wait(waitTime);
if (permits_ > 0) {
--waits_;
--permits_;
return true;
}
else { // got a time-out or false-alarm notify
waitTime = msecs - (System.currentTimeMillis() - startTime);
if (waitTime <= 0) {
--waits_;
return false;
}
}
}
}
catch(InterruptedException ex) {
--waits_;
notify();
throw ex;
}
}
}
}
public synchronized void release() {
++permits_;
notify();
}
/** Release N permits **/
public synchronized void release(long n) {
permits_ += n;
for (long i = 0; i < n; ++i) notify();
}
}
concurrent-dfsg-1.3.4/TimeoutSync.java 0000644 0001750 0001750 00000003636 10202157355 020202 0 ustar wbaer wbaer 0000000 0000000 /*
File: TimeoutSync.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
1Aug1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A TimeoutSync is an adaptor class that transforms all
* calls to acquire to instead invoke attempt with a predetermined
* timeout value.
*
* Sample Usage. A TimeoutSync can be used to obtain
* Timeouts for locks used in SyncCollections. For example:
* [ Introduction to this package. ]
* @see Sync
**/
public class TimeoutSync implements Sync {
protected final Sync sync_; // the adapted sync
protected final long timeout_; // timeout value
/**
* Create a TimeoutSync using the given Sync object, and
* using the given timeout value for all calls to acquire.
**/
public TimeoutSync(Sync sync, long timeout) {
sync_ = sync;
timeout_ = timeout;
}
public void acquire() throws InterruptedException {
if (!sync_.attempt(timeout_)) throw new TimeoutException(timeout_);
}
public boolean attempt(long msecs) throws InterruptedException {
return sync_.attempt(msecs);
}
public void release() {
sync_.release();
}
}
concurrent-dfsg-1.3.4/DirectExecutor.java 0000644 0001750 0001750 00000001737 10202157355 020650 0 ustar wbaer wbaer 0000000 0000000 /*
File: DirectExecutor.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
21Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
*
* An implementation of Executor that
* invokes the run method of the supplied command and then returns.
*
* [ Introduction to this package. ]
**/
public class DirectExecutor implements Executor {
/**
* Execute the given command directly in the current thread.
**/
public void execute(Runnable command) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
command.run();
}
}
concurrent-dfsg-1.3.4/CountDown.java 0000644 0001750 0001750 00000006534 10202157355 017637 0 ustar wbaer wbaer 0000000 0000000 /*
File: CountDown.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A CountDown can serve as a simple one-shot barrier.
* A Countdown is initialized
* with a given count value. Each release decrements the count.
* All acquires block until the count reaches zero. Upon reaching
* zero all current acquires are unblocked and all
* subsequent acquires pass without blocking. This is a one-shot
* phenomenon -- the count cannot be reset.
* If you need a version that resets the count, consider
* using a Barrier.
*
* Sample usage. Here are a set of classes in which
* a group of worker threads use a countdown to
* notify a driver when all threads are complete.
* [ Introduction to this package. ]
*
**/
public class CountDown implements Sync {
protected final int initialCount_;
protected int count_;
/** Create a new CountDown with given count value **/
public CountDown(int count) { count_ = initialCount_ = count; }
/*
This could use double-check, but doesn't out of concern
for surprising effects on user programs stemming
from lack of memory barriers with lack of synch.
*/
public void acquire() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
synchronized(this) {
while (count_ > 0)
wait();
}
}
public boolean attempt(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
synchronized(this) {
if (count_ <= 0)
return true;
else if (msecs <= 0)
return false;
else {
long waitTime = msecs;
long start = System.currentTimeMillis();
for (;;) {
wait(waitTime);
if (count_ <= 0)
return true;
else {
waitTime = msecs - (System.currentTimeMillis() - start);
if (waitTime <= 0)
return false;
}
}
}
}
}
/**
* Decrement the count.
* After the initialCount'th release, all current and future
* acquires will pass
**/
public synchronized void release() {
if (--count_ == 0)
notifyAll();
}
/** Return the initial count value **/
public int initialCount() { return initialCount_; }
/**
* Return the current count value.
* This is just a snapshot value, that may change immediately
* after returning.
**/
public synchronized int currentCount() { return count_; }
}
concurrent-dfsg-1.3.4/TimedCallable.java 0000644 0001750 0001750 00000003440 10202157355 020372 0 ustar wbaer wbaer 0000000 0000000 /*
TimedCallable.java
Originally written by Joseph Bowbeer and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Originally part of jozart.swingutils.
Adapted by Doug Lea for util.concurrent.
History:
Date Who What
11dec1999 dl Adapted for util.concurrent
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* TimedCallable runs a Callable function for a given length of time.
* The function is run in its own thread. If the function completes
* in time, its result is returned; otherwise the thread is interrupted
* and an InterruptedException is thrown.
*
* Note: TimedCallable will always return within the given time limit
* (modulo timer inaccuracies), but whether or not the worker thread
* stops in a timely fashion depends on the interrupt handling in the
* Callable function's implementation.
*
* @author Joseph Bowbeer
* @version 1.0
*
* [ Introduction to this package. ]
*/
public class TimedCallable extends ThreadFactoryUser implements Callable {
private final Callable function;
private final long millis;
public TimedCallable(Callable function, long millis) {
this.function = function;
this.millis = millis;
}
public Object call() throws Exception {
FutureResult result = new FutureResult();
Thread thread = getThreadFactory().newThread(result.setter(function));
thread.start();
try {
return result.timedGet(millis);
}
catch (InterruptedException ex) {
/* Stop thread if we were interrupted or timed-out
while waiting for the result. */
thread.interrupt();
throw ex;
}
}
}
concurrent-dfsg-1.3.4/SynchronizedChar.java 0000644 0001750 0001750 00000010072 10202157355 021164 0 ustar wbaer wbaer 0000000 0000000 /*
File: SynchronizedChar.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
19Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading synch for char instance variables.
*
* [ Introduction to this package. ]
**/
public class SynchronizedChar extends SynchronizedVariable implements Comparable, Cloneable {
protected char value_;
/**
* Make a new SynchronizedChar with the given initial value,
* and using its own internal lock.
**/
public SynchronizedChar(char initialValue) {
super();
value_ = initialValue;
}
/**
* Make a new SynchronizedChar with the given initial value,
* and using the supplied lock.
**/
public SynchronizedChar(char initialValue, Object lock) {
super(lock);
value_ = initialValue;
}
/**
* Return the current value
**/
public final char get() { synchronized(lock_) { return value_; } }
/**
* Set to newValue.
* @return the old value
**/
public char set(char newValue) {
synchronized (lock_) {
char old = value_;
value_ = newValue;
return old;
}
}
/**
* Set value to newValue only if it is currently assumedValue.
* @return true if successful
**/
public boolean commit(char assumedValue, char newValue) {
synchronized(lock_) {
boolean success = (assumedValue == value_);
if (success) value_ = newValue;
return success;
}
}
/**
* Atomically swap values with another SynchronizedChar.
* Uses identityHashCode to avoid deadlock when
* two SynchronizedChars attempt to simultaneously swap with each other.
* (Note: Ordering via identyHashCode is not strictly guaranteed
* by the language specification to return unique, orderable
* values, but in practice JVMs rely on them being unique.)
* @return the new value
**/
public char swap(SynchronizedChar other) {
if (other == this) return get();
SynchronizedChar fst = this;
SynchronizedChar snd = other;
if (System.identityHashCode(fst) > System.identityHashCode(snd)) {
fst = other;
snd = this;
}
synchronized(fst.lock_) {
synchronized(snd.lock_) {
fst.set(snd.set(fst.get()));
return get();
}
}
}
/**
* Add amount to value (i.e., set value += amount)
* @return the new value
**/
public char add(char amount) {
synchronized (lock_) {
return value_ += amount;
}
}
/**
* Subtract amount from value (i.e., set value -= amount)
* @return the new value
**/
public char subtract(char amount) {
synchronized (lock_) {
return value_ -= amount;
}
}
/**
* Multiply value by factor (i.e., set value *= factor)
* @return the new value
**/
public synchronized char multiply(char factor) {
synchronized (lock_) {
return value_ *= factor;
}
}
/**
* Divide value by factor (i.e., set value /= factor)
* @return the new value
**/
public char divide(char factor) {
synchronized (lock_) {
return value_ /= factor;
}
}
public int compareTo(char other) {
char val = get();
return (val < other)? -1 : (val == other)? 0 : 1;
}
public int compareTo(SynchronizedChar other) {
return compareTo(other.get());
}
public int compareTo(Object other) {
return compareTo((SynchronizedChar)other);
}
public boolean equals(Object other) {
if (other != null &&
other instanceof SynchronizedChar)
return get() == ((SynchronizedChar)other).get();
else
return false;
}
public int hashCode() { // same hash as Char
return (int)(get());
}
public String toString() { return String.valueOf(get()); }
}
concurrent-dfsg-1.3.4/SynchronizedByte.java 0000644 0001750 0001750 00000012613 10202157355 021215 0 ustar wbaer wbaer 0000000 0000000 /*
File: SynchronizedByte.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
19Jun1998 dl Create public version
15Apr2003 dl Removed redundant "synchronized" for multiply()
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading synch for byte instance variables.
*
* [ Introduction to this package. ]
**/
public class SynchronizedByte extends SynchronizedVariable implements Comparable, Cloneable {
protected byte value_;
/**
* Make a new SynchronizedByte with the given initial value,
* and using its own internal lock.
**/
public SynchronizedByte(byte initialValue) {
super();
value_ = initialValue;
}
/**
* Make a new SynchronizedByte with the given initial value,
* and using the supplied lock.
**/
public SynchronizedByte(byte initialValue, Object lock) {
super(lock);
value_ = initialValue;
}
/**
* Return the current value
**/
public final byte get() { synchronized(lock_) { return value_; } }
/**
* Set to newValue.
* @return the old value
**/
public byte set(byte newValue) {
synchronized (lock_) {
byte old = value_;
value_ = newValue;
return old;
}
}
/**
* Set value to newValue only if it is currently assumedValue.
* @return true if successful
**/
public boolean commit(byte assumedValue, byte newValue) {
synchronized(lock_) {
boolean success = (assumedValue == value_);
if (success) value_ = newValue;
return success;
}
}
/**
* Atomically swap values with another SynchronizedByte.
* Uses identityHashCode to avoid deadlock when
* two SynchronizedBytes attempt to simultaneously swap with each other.
* (Note: Ordering via identyHashCode is not strictly guaranteed
* by the language specification to return unique, orderable
* values, but in practice JVMs rely on them being unique.)
* @return the new value
**/
public byte swap(SynchronizedByte other) {
if (other == this) return get();
SynchronizedByte fst = this;
SynchronizedByte snd = other;
if (System.identityHashCode(fst) > System.identityHashCode(snd)) {
fst = other;
snd = this;
}
synchronized(fst.lock_) {
synchronized(snd.lock_) {
fst.set(snd.set(fst.get()));
return get();
}
}
}
/**
* Increment the value.
* @return the new value
**/
public byte increment() {
synchronized (lock_) {
return ++value_;
}
}
/**
* Decrement the value.
* @return the new value
**/
public byte decrement() {
synchronized (lock_) {
return --value_;
}
}
/**
* Add amount to value (i.e., set value += amount)
* @return the new value
**/
public byte add(byte amount) {
synchronized (lock_) {
return value_ += amount;
}
}
/**
* Subtract amount from value (i.e., set value -= amount)
* @return the new value
**/
public byte subtract(byte amount) {
synchronized (lock_) {
return value_ -= amount;
}
}
/**
* Multiply value by factor (i.e., set value *= factor)
* @return the new value
**/
public byte multiply(byte factor) {
synchronized (lock_) {
return value_ *= factor;
}
}
/**
* Divide value by factor (i.e., set value /= factor)
* @return the new value
**/
public byte divide(byte factor) {
synchronized (lock_) {
return value_ /= factor;
}
}
/**
* Set the value to the negative of its old value
* @return the new value
**/
public byte negate() {
synchronized (lock_) {
value_ = (byte)(-value_);
return value_;
}
}
/**
* Set the value to its complement
* @return the new value
**/
public byte complement() {
synchronized (lock_) {
value_ = (byte)~value_;
return value_;
}
}
/**
* Set value to value & b.
* @return the new value
**/
public byte and(byte b) {
synchronized (lock_) {
value_ = (byte)(value_ & b);
return value_;
}
}
/**
* Set value to value | b.
* @return the new value
**/
public byte or(byte b) {
synchronized (lock_) {
value_ = (byte)(value_ | b);
return value_;
}
}
/**
* Set value to value ^ b.
* @return the new value
**/
public byte xor(byte b) {
synchronized (lock_) {
value_ = (byte)(value_ ^ b);
return value_;
}
}
public int compareTo(byte other) {
byte val = get();
return (val < other)? -1 : (val == other)? 0 : 1;
}
public int compareTo(SynchronizedByte other) {
return compareTo(other.get());
}
public int compareTo(Object other) {
return compareTo((SynchronizedByte)other);
}
public boolean equals(Object other) {
if (other != null &&
other instanceof SynchronizedByte)
return get() == ((SynchronizedByte)other).get();
else
return false;
}
public int hashCode() {
return (int)(get());
}
public String toString() { return Byte.toString(get()); }
}
concurrent-dfsg-1.3.4/SynchronizedShort.java 0000644 0001750 0001750 00000012702 10202157355 021410 0 ustar wbaer wbaer 0000000 0000000 /*
File: SynchronizedShort.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
19Jun1998 dl Create public version
15Apr2003 dl Removed redundant "synchronized" for multiply()
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading synch for short instance variables.
*
* [ Introduction to this package. ]
**/
public class SynchronizedShort extends SynchronizedVariable implements Comparable, Cloneable {
protected short value_;
/**
* Make a new SynchronizedShort with the given initial value,
* and using its own internal lock.
**/
public SynchronizedShort(short initialValue) {
super();
value_ = initialValue;
}
/**
* Make a new SynchronizedShort with the given initial value,
* and using the supplied lock.
**/
public SynchronizedShort(short initialValue, Object lock) {
super(lock);
value_ = initialValue;
}
/**
* Return the current value
**/
public final short get() { synchronized(lock_) { return value_; } }
/**
* Set to newValue.
* @return the old value
**/
public short set(short newValue) {
synchronized (lock_) {
short old = value_;
value_ = newValue;
return old;
}
}
/**
* Set value to newValue only if it is currently assumedValue.
* @return true if successful
**/
public boolean commit(short assumedValue, short newValue) {
synchronized(lock_) {
boolean success = (assumedValue == value_);
if (success) value_ = newValue;
return success;
}
}
/**
* Atomically swap values with another SynchronizedShort.
* Uses identityHashCode to avoid deadlock when
* two SynchronizedShorts attempt to simultaneously swap with each other.
* (Note: Ordering via identyHashCode is not strictly guaranteed
* by the language specification to return unique, orderable
* values, but in practice JVMs rely on them being unique.)
* @return the new value
**/
public short swap(SynchronizedShort other) {
if (other == this) return get();
SynchronizedShort fst = this;
SynchronizedShort snd = other;
if (System.identityHashCode(fst) > System.identityHashCode(snd)) {
fst = other;
snd = this;
}
synchronized(fst.lock_) {
synchronized(snd.lock_) {
fst.set(snd.set(fst.get()));
return get();
}
}
}
/**
* Increment the value.
* @return the new value
**/
public short increment() {
synchronized (lock_) {
return ++value_;
}
}
/**
* Decrement the value.
* @return the new value
**/
public short decrement() {
synchronized (lock_) {
return --value_;
}
}
/**
* Add amount to value (i.e., set value += amount)
* @return the new value
**/
public short add(short amount) {
synchronized (lock_) {
return value_ += amount;
}
}
/**
* Subtract amount from value (i.e., set value -= amount)
* @return the new value
**/
public short subtract(short amount) {
synchronized (lock_) {
return value_ -= amount;
}
}
/**
* Multiply value by factor (i.e., set value *= factor)
* @return the new value
**/
public short multiply(short factor) {
synchronized (lock_) {
return value_ *= factor;
}
}
/**
* Divide value by factor (i.e., set value /= factor)
* @return the new value
**/
public short divide(short factor) {
synchronized (lock_) {
return value_ /= factor;
}
}
/**
* Set the value to the negative of its old value
* @return the new value
**/
public short negate() {
synchronized (lock_) {
value_ = (short)(-value_);
return value_;
}
}
/**
* Set the value to its complement
* @return the new value
**/
public short complement() {
synchronized (lock_) {
value_ = (short)(~value_);
return value_;
}
}
/**
* Set value to value & b.
* @return the new value
**/
public short and(short b) {
synchronized (lock_) {
value_ = (short)(value_ & b);
return value_;
}
}
/**
* Set value to value | b.
* @return the new value
**/
public short or(short b) {
synchronized (lock_) {
value_ = (short)(value_ | b);
return value_;
}
}
/**
* Set value to value ^ b.
* @return the new value
**/
public short xor(short b) {
synchronized (lock_) {
value_ = (short)(value_ ^ b);
return value_;
}
}
public int compareTo(short other) {
short val = get();
return (val < other)? -1 : (val == other)? 0 : 1;
}
public int compareTo(SynchronizedShort other) {
return compareTo(other.get());
}
public int compareTo(Object other) {
return compareTo((SynchronizedShort)other);
}
public boolean equals(Object other) {
if (other != null &&
other instanceof SynchronizedShort)
return get() == ((SynchronizedShort)other).get();
else
return false;
}
public int hashCode() {
return (int)(get());
}
public String toString() { return String.valueOf(get()); }
}
concurrent-dfsg-1.3.4/LinkedNode.java 0000644 0001750 0001750 00000001534 10202157355 017726 0 ustar wbaer wbaer 0000000 0000000 /*
File: LinkedNode.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
25may2000 dl Change class access to public
26nov2001 dl Added no-arg constructor, all public access.
*/
package EDU.oswego.cs.dl.util.concurrent;
/** A standard linked list node used in various queue classes **/
public class LinkedNode {
public Object value;
public LinkedNode next;
public LinkedNode() {}
public LinkedNode(Object x) { value = x; }
public LinkedNode(Object x, LinkedNode n) { value = x; next = n; }
}
concurrent-dfsg-1.3.4/WaitFreeQueue.java 0000644 0001750 0001750 00000013755 10202157355 020435 0 ustar wbaer wbaer 0000000 0000000 /*
File: WaitFreeQueue.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
16Jun1998 dl Create public version
5Aug1998 dl replaced int counters with longs
17nov2001 dl Simplify given Bill Pugh's observation
that counted pointers are unnecessary.
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A wait-free linked list based queue implementation.
*
*
* While this class conforms to the full Channel interface, only the
*
*
* This class is adapted from the algorithm described in Simple,
* Fast, and Practical Non-Blocking and Blocking Concurrent Queue
* Algorithms by Maged M. Michael and Michael L. Scott. This
* implementation is not strictly wait-free since it relies on locking
* for basic atomicity and visibility requirements. Locks can impose
* unbounded waits, although this should not be a major practical
* concern here since each lock is held for the duration of only a few
* statements. (However, the overhead of using so many locks can make
* it less attractive than other Channel implementations on JVMs where
* locking operations are very slow.)
*
* @see BoundedLinkedQueue
* @see LinkedQueue
*
* [ Introduction to this package. ]
**/
public class WaitFreeQueue implements Channel {
/*
This is a straightforward adaptation of Michael & Scott
algorithm, with CAS's simulated via per-field locks,
and without version numbers for pointers since, under
Java Garbage Collection, you can never see the "wrong"
node with the same address as the one you think you have.
*/
/** List nodes for Queue **/
protected final static class Node {
protected final Object value;
protected volatile Node next;
/** Make a new node with indicated item, and null link **/
protected Node(Object x) { value = x; }
/** Simulate a CAS operation for 'next' field **/
protected synchronized boolean CASNext(Node oldNext, Node newNext) {
if (next == oldNext) {
next = newNext;
return true;
}
else
return false;
}
}
/** Head of list is always a dummy node **/
protected volatile Node head = new Node(null);
/** Pointer to last node on list **/
protected volatile Node tail = head;
/** Lock for simulating CAS for tail field **/
protected final Object tailLock = new Object();
/** Simulate CAS for head field, using 'this' lock **/
protected synchronized boolean CASHead(Node oldHead, Node newHead) {
if (head == oldHead) {
head = newHead;
return true;
}
else
return false;
}
/** Simulate CAS for tail field **/
protected boolean CASTail(Node oldTail, Node newTail) {
synchronized(tailLock) {
if (tail == oldTail) {
tail = newTail;
return true;
}
else
return false;
}
}
public void put(Object x) throws InterruptedException {
if (x == null) throw new IllegalArgumentException();
if (Thread.interrupted()) throw new InterruptedException();
Node n = new Node(x);
for(;;) {
Node t = tail;
// Try to link new node to end of list.
if (t.CASNext(null, n)) {
// Must now change tail field.
// This CAS might fail, but if so, it will be fixed by others.
CASTail(t, n);
return;
}
// If cannot link, help out a previous failed attempt to move tail
CASTail(t, t.next);
}
}
public boolean offer(Object x, long msecs) throws InterruptedException {
put(x);
return true;
}
/** Main dequeue algorithm, called by poll, take. **/
protected Object extract() throws InterruptedException {
for (;;) {
Node h = head;
Node first = h.next;
if (first == null)
return null;
Object result = first.value;
if (CASHead(h, first))
return result;
}
}
public Object peek() {
Node first = head.next;
if (first == null)
return null;
// Note: This synch unnecessary after JSR-133.
// It exists only to guarantee visibility of returned object,
// No other synch is needed, but "old" memory model requires one.
synchronized(this) {
return first.value;
}
}
/**
* Spin until poll returns a non-null value.
* You probably don't want to call this method.
* A Thread.sleep(0) is performed on each iteration
* as a heuristic to reduce contention. If you would
* rather use, for example, an exponential backoff,
* you could manually set this up using poll.
**/
public Object take() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
for(;;) {
Object x = extract();
if (x != null)
return x;
else
Thread.sleep(0);
}
}
/**
* Spin until poll returns a non-null value or time elapses.
* if msecs is positive, a Thread.sleep(0) is performed on each iteration
* as a heuristic to reduce contention.
**/
public Object poll(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
if (msecs <= 0)
return extract();
long startTime = System.currentTimeMillis();
for(;;) {
Object x = extract();
if (x != null)
return x;
else if (System.currentTimeMillis() - startTime >= msecs)
return null;
else
Thread.sleep(0);
}
}
}
concurrent-dfsg-1.3.4/ClockDaemon.java 0000644 0001750 0001750 00000027777 10202157355 020112 0 ustar wbaer wbaer 0000000 0000000 /*
File: ClockDaemon.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
29Aug1998 dl created initial public version
17dec1998 dl null out thread after shutdown
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.util.Comparator;
import java.util.Date;
/**
* A general-purpose time-based daemon, vaguely similar in functionality
* to common system-level utilities such as
* All commands are executed by the single background thread.
* The thread is not actually started until the first
* request is encountered. Also, if the
* thread is stopped for any reason, one is started upon encountering
* the next request, or
* If you would instead like commands run in their own threads, you can
* use as arguments Runnable commands that start their own threads
* (or perhaps wrap within ThreadedExecutors).
*
* You can also use multiple
* daemon objects, each using a different background thread. However,
* one of the reasons for using a time daemon is to pool together
* processing of infrequent tasks using a single background thread.
*
* Background threads are created using a ThreadFactory. The
* default factory does not
* automatically
* The class uses Java timed waits for scheduling. These can vary
* in precision across platforms, and provide no real-time guarantees
* about meeting deadlines.
* [ Introduction to this package. ]
**/
public class ClockDaemon extends ThreadFactoryUser {
/** tasks are maintained in a standard priority queue **/
protected final Heap heap_ = new Heap(DefaultChannelCapacity.get());
protected static class TaskNode implements Comparable {
final Runnable command; // The command to run
final long period; // The cycle period, or -1 if not periodic
private long timeToRun_; // The time to run command
// Cancellation does not immediately remove node, it just
// sets up lazy deletion bit, so is thrown away when next
// encountered in run loop
private boolean cancelled_ = false;
// Access to cancellation status and and run time needs sync
// since they can be written and read in different threads
synchronized void setCancelled() { cancelled_ = true; }
synchronized boolean getCancelled() { return cancelled_; }
synchronized void setTimeToRun(long w) { timeToRun_ = w; }
synchronized long getTimeToRun() { return timeToRun_; }
public int compareTo(Object other) {
long a = getTimeToRun();
long b = ((TaskNode)(other)).getTimeToRun();
return (a < b)? -1 : ((a == b)? 0 : 1);
}
TaskNode(long w, Runnable c, long p) {
timeToRun_ = w; command = c; period = p;
}
TaskNode(long w, Runnable c) { this(w, c, -1); }
}
/**
* Execute the given command at the given time.
* @param date -- the absolute time to run the command, expressed
* as a java.util.Date.
* @param command -- the command to run at the given time.
* @return taskID -- an opaque reference that can be used to cancel execution request
**/
public Object executeAt(Date date, Runnable command) {
TaskNode task = new TaskNode(date.getTime(), command);
heap_.insert(task);
restart();
return task;
}
/**
* Excecute the given command after waiting for the given delay.
*
* Sample Usage.
* You can use a ClockDaemon to arrange timeout callbacks to break out
* of stuck IO. For example (code sketch):
*
* Sample Usage. Here is one way
* to update Swing components acting as progress indicators for
* long-running actions.
* [ Introduction to this package. ]
**/
public abstract class SemaphoreControlledChannel implements BoundedChannel {
protected final Semaphore putGuard_;
protected final Semaphore takeGuard_;
protected int capacity_;
/**
* Create a channel with the given capacity and default
* semaphore implementation
* @exception IllegalArgumentException if capacity less or equal to zero
**/
public SemaphoreControlledChannel(int capacity)
throws IllegalArgumentException {
if (capacity <= 0) throw new IllegalArgumentException();
capacity_ = capacity;
putGuard_ = new Semaphore(capacity);
takeGuard_ = new Semaphore(0);
}
/**
* Create a channel with the given capacity and
* semaphore implementations instantiated from the supplied class
* @exception IllegalArgumentException if capacity less or equal to zero.
* @exception NoSuchMethodException If class does not have constructor
* that intializes permits
* @exception SecurityException if constructor information
* not accessible
* @exception InstantiationException if semaphore class is abstract
* @exception IllegalAccessException if constructor cannot be called
* @exception InvocationTargetException if semaphore constructor throws an
* exception
**/
public SemaphoreControlledChannel(int capacity, Class semaphoreClass)
throws IllegalArgumentException,
NoSuchMethodException,
SecurityException,
InstantiationException,
IllegalAccessException,
InvocationTargetException {
if (capacity <= 0) throw new IllegalArgumentException();
capacity_ = capacity;
Class[] longarg = { Long.TYPE };
Constructor ctor = semaphoreClass.getDeclaredConstructor(longarg);
Long[] cap = { new Long(capacity) };
putGuard_ = (Semaphore)(ctor.newInstance(cap));
Long[] zero = { new Long(0) };
takeGuard_ = (Semaphore)(ctor.newInstance(zero));
}
public int capacity() { return capacity_; }
/**
* Return the number of elements in the buffer.
* This is only a snapshot value, that may change
* immediately after returning.
**/
public int size() { return (int)(takeGuard_.permits()); }
/**
* Internal mechanics of put.
**/
protected abstract void insert(Object x);
/**
* Internal mechanics of take.
**/
protected abstract Object extract();
public void put(Object x) throws InterruptedException {
if (x == null) throw new IllegalArgumentException();
if (Thread.interrupted()) throw new InterruptedException();
putGuard_.acquire();
try {
insert(x);
takeGuard_.release();
}
catch (ClassCastException ex) {
putGuard_.release();
throw ex;
}
}
public boolean offer(Object x, long msecs) throws InterruptedException {
if (x == null) throw new IllegalArgumentException();
if (Thread.interrupted()) throw new InterruptedException();
if (!putGuard_.attempt(msecs))
return false;
else {
try {
insert(x);
takeGuard_.release();
return true;
}
catch (ClassCastException ex) {
putGuard_.release();
throw ex;
}
}
}
public Object take() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
takeGuard_.acquire();
try {
Object x = extract();
putGuard_.release();
return x;
}
catch (ClassCastException ex) {
takeGuard_.release();
throw ex;
}
}
public Object poll(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
if (!takeGuard_.attempt(msecs))
return null;
else {
try {
Object x = extract();
putGuard_.release();
return x;
}
catch (ClassCastException ex) {
takeGuard_.release();
throw ex;
}
}
}
}
concurrent-dfsg-1.3.4/FIFOSemaphore.java 0000644 0001750 0001750 00000004751 10202157355 020305 0 ustar wbaer wbaer 0000000 0000000 /*
File: FIFOSemaphore.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A First-in/First-out implementation of a Semaphore.
* Waiting requests will be satisified in
* the order that the processing of those requests got to a certain point.
* If this sounds vague it is meant to be. FIFO implies a
* logical timestamping at some point in the processing of the
* request. To simplify things we don't actually timestamp but
* simply store things in a FIFO queue. Thus the order in which
* requests enter the queue will be the order in which they come
* out. This order need not have any relationship to the order in
* which requests were made, nor the order in which requests
* actually return to the caller. These depend on Java thread
* scheduling which is not guaranteed to be predictable (although
* JVMs tend not to go out of their way to be unfair).
* [ Introduction to this package. ]
**/
public class FIFOSemaphore extends QueuedSemaphore {
/**
* Create a Semaphore with the given initial number of permits.
* Using a seed of one makes the semaphore act as a mutual exclusion lock.
* Negative seeds are also allowed, in which case no acquires will proceed
* until the number of releases has pushed the number of permits past 0.
**/
public FIFOSemaphore(long initialPermits) {
super(new FIFOWaitQueue(), initialPermits);
}
/**
* Simple linked list queue used in FIFOSemaphore.
* Methods are not synchronized; they depend on synch of callers
**/
protected static class FIFOWaitQueue extends WaitQueue {
protected WaitNode head_ = null;
protected WaitNode tail_ = null;
protected void insert(WaitNode w) {
if (tail_ == null)
head_ = tail_ = w;
else {
tail_.next = w;
tail_ = w;
}
}
protected WaitNode extract() {
if (head_ == null)
return null;
else {
WaitNode w = head_;
head_ = w.next;
if (head_ == null) tail_ = null;
w.next = null;
return w;
}
}
}
}
concurrent-dfsg-1.3.4/SynchronizedFloat.java 0000644 0001750 0001750 00000010232 10202157355 021352 0 ustar wbaer wbaer 0000000 0000000 /*
File: SynchronizedFloat.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
19Jun1998 dl Create public version
15Apr2003 dl Removed redundant "synchronized" for multiply()
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading synch for float instance variables.
*
* [ Introduction to this package. ]
**/
public class SynchronizedFloat extends SynchronizedVariable implements Comparable, Cloneable {
protected float value_;
/**
* Make a new SynchronizedFloat with the given initial value,
* and using its own internal lock.
**/
public SynchronizedFloat(float initialValue) {
super();
value_ = initialValue;
}
/**
* Make a new SynchronizedFloat with the given initial value,
* and using the supplied lock.
**/
public SynchronizedFloat(float initialValue, Object lock) {
super(lock);
value_ = initialValue;
}
/**
* Return the current value
**/
public final float get() { synchronized(lock_) { return value_; } }
/**
* Set to newValue.
* @return the old value
**/
public float set(float newValue) {
synchronized (lock_) {
float old = value_;
value_ = newValue;
return old;
}
}
/**
* Set value to newValue only if it is currently assumedValue.
* @return true if successful
**/
public boolean commit(float assumedValue, float newValue) {
synchronized(lock_) {
boolean success = (assumedValue == value_);
if (success) value_ = newValue;
return success;
}
}
/**
* Atomically swap values with another SynchronizedFloat.
* Uses identityHashCode to avoid deadlock when
* two SynchronizedFloats attempt to simultaneously swap with each other.
* (Note: Ordering via identyHashCode is not strictly guaranteed
* by the language specification to return unique, orderable
* values, but in practice JVMs rely on them being unique.)
* @return the new value
**/
public float swap(SynchronizedFloat other) {
if (other == this) return get();
SynchronizedFloat fst = this;
SynchronizedFloat snd = other;
if (System.identityHashCode(fst) > System.identityHashCode(snd)) {
fst = other;
snd = this;
}
synchronized(fst.lock_) {
synchronized(snd.lock_) {
fst.set(snd.set(fst.get()));
return get();
}
}
}
/**
* Add amount to value (i.e., set value += amount)
* @return the new value
**/
public float add(float amount) {
synchronized (lock_) {
return value_ += amount;
}
}
/**
* Subtract amount from value (i.e., set value -= amount)
* @return the new value
**/
public float subtract(float amount) {
synchronized (lock_) {
return value_ -= amount;
}
}
/**
* Multiply value by factor (i.e., set value *= factor)
* @return the new value
**/
public float multiply(float factor) {
synchronized (lock_) {
return value_ *= factor;
}
}
/**
* Divide value by factor (i.e., set value /= factor)
* @return the new value
**/
public float divide(float factor) {
synchronized (lock_) {
return value_ /= factor;
}
}
public int compareTo(float other) {
float val = get();
return (val < other)? -1 : (val == other)? 0 : 1;
}
public int compareTo(SynchronizedFloat other) {
return compareTo(other.get());
}
public int compareTo(Object other) {
return compareTo((SynchronizedFloat)other);
}
public boolean equals(Object other) {
if (other != null &&
other instanceof SynchronizedFloat)
return get() == ((SynchronizedFloat)other).get();
else
return false;
}
public int hashCode() {
return Float.floatToIntBits(get());
}
public String toString() { return String.valueOf(get()); }
}
concurrent-dfsg-1.3.4/Slot.java 0000644 0001750 0001750 00000004473 10202157355 016640 0 ustar wbaer wbaer 0000000 0000000 /*
File: Slot.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
25aug1998 dl added peek
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.lang.reflect.*;
/**
* A one-slot buffer, using semaphores to control access.
* Slots are usually more efficient and controllable than using other
* bounded buffers implementations with capacity of 1.
*
* Among other applications, Slots can be convenient in token-passing
* designs: Here. the Slot holds a some object serving as a token,
* that can be obtained
* and returned by various threads.
*
* [ Introduction to this package. ]
**/
public class Slot extends SemaphoreControlledChannel {
/**
* Create a buffer with the given capacity, using
* the supplied Semaphore class for semaphores.
* @exception NoSuchMethodException If class does not have constructor
* that intializes permits
* @exception SecurityException if constructor information
* not accessible
* @exception InstantiationException if semaphore class is abstract
* @exception IllegalAccessException if constructor cannot be called
* @exception InvocationTargetException if semaphore constructor throws an
* exception
**/
public Slot(Class semaphoreClass)
throws NoSuchMethodException,
SecurityException,
InstantiationException,
IllegalAccessException,
InvocationTargetException {
super(1, semaphoreClass);
}
/**
* Create a new Slot using default Semaphore implementations
**/
public Slot() {
super(1);
}
/** The slot **/
protected Object item_ = null;
/** Set the item in preparation for a take **/
protected synchronized void insert(Object x) {
item_ = x;
}
/** Take item known to exist **/
protected synchronized Object extract() {
Object x = item_;
item_ = null;
return x;
}
public synchronized Object peek() {
return item_;
}
}
concurrent-dfsg-1.3.4/WaitableDouble.java 0000644 0001750 0001750 00000010056 10202157355 020574 0 ustar wbaer wbaer 0000000 0000000 /*
File: WaitableDouble.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
23Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading waiting and signalling operations
* on single double variables.
*
* [ Introduction to this package. ]
**/
public class WaitableDouble extends SynchronizedDouble {
/**
* Make a new WaitableDouble with the given initial value,
* and using its own internal lock.
**/
public WaitableDouble(double initialValue) {
super(initialValue);
}
/**
* Make a new WaitableDouble with the given initial value,
* and using the supplied lock.
**/
public WaitableDouble(double initialValue, Object lock) {
super(initialValue, lock);
}
public double set(double newValue) {
synchronized (lock_) {
lock_.notifyAll();
return super.set(newValue);
}
}
public boolean commit(double assumedValue, double newValue) {
synchronized (lock_) {
boolean success = super.commit(assumedValue, newValue);
if (success) lock_.notifyAll();
return success;
}
}
public double add(double amount) {
synchronized (lock_) {
lock_.notifyAll();
return super.add(amount);
}
}
public double subtract(double amount) {
synchronized (lock_) {
lock_.notifyAll();
return super.subtract(amount);
}
}
public double multiply(double factor) {
synchronized (lock_) {
lock_.notifyAll();
return super.multiply(factor);
}
}
public double divide(double factor) {
synchronized (lock_) {
lock_.notifyAll();
return super.divide(factor);
}
}
/**
* Wait until value equals c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenEqual(double c, Runnable action) throws InterruptedException {
synchronized(lock_) {
while (!(value_ == c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value not equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenNotEqual(double c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ != c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value less than or equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenLessEqual(double c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ <= c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value less than c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenLess(double c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ < c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value greater than or equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenGreaterEqual(double c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ >= c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value greater than c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenGreater(double c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ > c)) lock_.wait();
if (action != null) action.run();
}
}
}
concurrent-dfsg-1.3.4/DefaultChannelCapacity.java 0000644 0001750 0001750 00000003343 10202157355 022245 0 ustar wbaer wbaer 0000000 0000000 /*
File: DefaultChannelCapacity.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A utility class to set the default capacity of
* BoundedChannel
* implementations that otherwise require a capacity argument
* @see BoundedChannel
* [ Introduction to this package. ]
**/
public class DefaultChannelCapacity {
/** The initial value of the default capacity is 1024 **/
public static final int INITIAL_DEFAULT_CAPACITY = 1024;
/** the current default capacity **/
private static final SynchronizedInt defaultCapacity_ =
new SynchronizedInt(INITIAL_DEFAULT_CAPACITY);
/**
* Set the default capacity used in
* default (no-argument) constructor for BoundedChannels
* that otherwise require a capacity argument.
* @exception IllegalArgumentException if capacity less or equal to zero
*/
public static void set(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
defaultCapacity_.set(capacity);
}
/**
* Get the default capacity used in
* default (no-argument) constructor for BoundedChannels
* that otherwise require a capacity argument.
* Initial value is [ Introduction to this package. ]
* @see SyncCollection
**/
public class SyncSortedSet extends SyncSet implements SortedSet {
/**
* Create a new SyncSortedSet protecting the given collection,
* and using the given sync to control both reader and writer methods.
* Common, reasonable choices for the sync argument include
* Mutex, ReentrantLock, and Semaphores initialized to 1.
**/
public SyncSortedSet(SortedSet set, Sync sync) {
super (set, sync);
}
/**
* Create a new SyncSortedSet protecting the given set,
* and using the given ReadWriteLock to control reader and writer methods.
**/
public SyncSortedSet(SortedSet set, ReadWriteLock rwl) {
super (set, rwl.readLock(), rwl.writeLock());
}
/**
* Create a new SyncSortedSet protecting the given set,
* and using the given pair of locks to control reader and writer methods.
**/
public SyncSortedSet(SortedSet set, Sync readLock, Sync writeLock) {
super(set, readLock, writeLock);
}
protected SortedSet baseSortedSet() {
return (SortedSet)c_;
}
public Comparator comparator() {
boolean wasInterrupted = beforeRead();
try {
return baseSortedSet().comparator();
}
finally {
afterRead(wasInterrupted);
}
}
public Object first() {
boolean wasInterrupted = beforeRead();
try {
return baseSortedSet().first();
}
finally {
afterRead(wasInterrupted);
}
}
public Object last() {
boolean wasInterrupted = beforeRead();
try {
return baseSortedSet().last();
}
finally {
afterRead(wasInterrupted);
}
}
public SortedSet subSet(Object fromElement, Object toElement) {
boolean wasInterrupted = beforeRead();
try {
return new SyncSortedSet(baseSortedSet().subSet(fromElement, toElement),
rd_, wr_);
}
finally {
afterRead(wasInterrupted);
}
}
public SortedSet headSet(Object toElement) {
boolean wasInterrupted = beforeRead();
try {
return new SyncSortedSet(baseSortedSet().headSet(toElement),
rd_, wr_);
}
finally {
afterRead(wasInterrupted);
}
}
public SortedSet tailSet(Object fromElement) {
boolean wasInterrupted = beforeRead();
try {
return new SyncSortedSet(baseSortedSet().tailSet(fromElement),
rd_, wr_);
}
finally {
afterRead(wasInterrupted);
}
}
}
concurrent-dfsg-1.3.4/WaitableRef.java 0000644 0001750 0001750 00000005370 10202157355 020101 0 ustar wbaer wbaer 0000000 0000000 /*
File: WaitableRef.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
19Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading synch for Object reference instance variables.
*
* [ Introduction to this package. ]
**/
public class WaitableRef extends SynchronizedRef {
/**
* Create a WaitableRef initially holding the given reference
* and using its own internal lock.
**/
public WaitableRef(Object initialValue) {
super(initialValue);
}
/**
* Make a new WaitableRef with the given initial value,
* and using the supplied lock.
**/
public WaitableRef(Object initialValue, Object lock) {
super(initialValue, lock);
}
public Object set(Object newValue) {
synchronized (lock_) {
lock_.notifyAll();
return super.set(newValue);
}
}
public boolean commit(Object assumedValue, Object newValue) {
synchronized (lock_) {
boolean success = super.commit(assumedValue, newValue);
if (success) lock_.notifyAll();
return success;
}
}
/**
* Wait until value is null, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenNull(Runnable action) throws InterruptedException {
synchronized (lock_) {
while (value_ != null) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value is nonnull, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenNotNull(Runnable action) throws InterruptedException {
synchronized (lock_) {
while (value_ == null) lock_.wait();
if (action != null) action.run();
}
}
/**
* Wait until value equals c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenEqual(Object c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ == c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value not equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenNotEqual(Object c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ != c)) lock_.wait();
if (action != null) action.run();
}
}
}
concurrent-dfsg-1.3.4/SynchronizedLong.java 0000644 0001750 0001750 00000012471 10202157355 021213 0 ustar wbaer wbaer 0000000 0000000 /*
File: SynchronizedLong.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
19Jun1998 dl Create public version
15Apr2003 dl Removed redundant "synchronized" for multiply()
23jan04 dl synchronize self-swap case for swap
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading synch for long instance variables.
*
* [ Introduction to this package. ]
**/
public class SynchronizedLong extends SynchronizedVariable implements Comparable, Cloneable {
protected long value_;
/**
* Make a new SynchronizedLong with the given initial value,
* and using its own internal lock.
**/
public SynchronizedLong(long initialValue) {
super();
value_ = initialValue;
}
/**
* Make a new SynchronizedLong with the given initial value,
* and using the supplied lock.
**/
public SynchronizedLong(long initialValue, Object lock) {
super(lock);
value_ = initialValue;
}
/**
* Return the current value
**/
public final long get() { synchronized(lock_) { return value_; } }
/**
* Set to newValue.
* @return the old value
**/
public long set(long newValue) {
synchronized (lock_) {
long old = value_;
value_ = newValue;
return old;
}
}
/**
* Set value to newValue only if it is currently assumedValue.
* @return true if successful
**/
public boolean commit(long assumedValue, long newValue) {
synchronized(lock_) {
boolean success = (assumedValue == value_);
if (success) value_ = newValue;
return success;
}
}
/**
* Atomically swap values with another SynchronizedLong.
* Uses identityHashCode to avoid deadlock when
* two SynchronizedLongs attempt to simultaneously swap with each other.
* @return the new value
**/
public long swap(SynchronizedLong other) {
if (other == this) return get();
SynchronizedLong fst = this;
SynchronizedLong snd = other;
if (System.identityHashCode(fst) > System.identityHashCode(snd)) {
fst = other;
snd = this;
}
synchronized(fst.lock_) {
synchronized(snd.lock_) {
fst.set(snd.set(fst.get()));
return get();
}
}
}
/**
* Increment the value.
* @return the new value
**/
public long increment() {
synchronized (lock_) {
return ++value_;
}
}
/**
* Decrement the value.
* @return the new value
**/
public long decrement() {
synchronized (lock_) {
return --value_;
}
}
/**
* Add amount to value (i.e., set value += amount)
* @return the new value
**/
public long add(long amount) {
synchronized (lock_) {
return value_ += amount;
}
}
/**
* Subtract amount from value (i.e., set value -= amount)
* @return the new value
**/
public long subtract(long amount) {
synchronized (lock_) {
return value_ -= amount;
}
}
/**
* Multiply value by factor (i.e., set value *= factor)
* @return the new value
**/
public long multiply(long factor) {
synchronized (lock_) {
return value_ *= factor;
}
}
/**
* Divide value by factor (i.e., set value /= factor)
* @return the new value
**/
public long divide(long factor) {
synchronized (lock_) {
return value_ /= factor;
}
}
/**
* Set the value to the negative of its old value
* @return the new value
**/
public long negate() {
synchronized (lock_) {
value_ = -value_;
return value_;
}
}
/**
* Set the value to its complement
* @return the new value
**/
public long complement() {
synchronized (lock_) {
value_ = ~value_;
return value_;
}
}
/**
* Set value to value & b.
* @return the new value
**/
public long and(long b) {
synchronized (lock_) {
value_ = value_ & b;
return value_;
}
}
/**
* Set value to value | b.
* @return the new value
**/
public long or(long b) {
synchronized (lock_) {
value_ = value_ | b;
return value_;
}
}
/**
* Set value to value ^ b.
* @return the new value
**/
public long xor(long b) {
synchronized (lock_) {
value_ = value_ ^ b;
return value_;
}
}
public int compareTo(long other) {
long val = get();
return (val < other)? -1 : (val == other)? 0 : 1;
}
public int compareTo(SynchronizedLong other) {
return compareTo(other.get());
}
public int compareTo(Object other) {
return compareTo((SynchronizedLong)other);
}
public boolean equals(Object other) {
if (other != null &&
other instanceof SynchronizedLong)
return get() == ((SynchronizedLong)other).get();
else
return false;
}
public int hashCode() { // same expression as java.lang.Long
long v = get();
return (int)(v ^ (v >> 32));
}
public String toString() { return String.valueOf(get()); }
}
concurrent-dfsg-1.3.4/Rendezvous.java 0000644 0001750 0001750 00000031750 10202157355 020061 0 ustar wbaer wbaer 0000000 0000000 /*
File: Rendezvous.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
30Jul1998 dl Minor code simplifications
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A rendezvous is a barrier that:
*
* Rendezvous use an all-or-none breakage model
* for failed synchronization attempts: If threads
* leave a rendezvous point prematurely because of timeout
* or interruption, others will also leave abnormally
* (via BrokenBarrierException), until
* the rendezvous is
* While any positive number (including 1) of parties can
* be handled, the most common case is to have two parties.
*
* Sample Usage
* Here are the highlights of a class that uses a Rendezvous 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.
* [ Introduction to this package. ]
**/
public class Rendezvous implements Barrier {
/**
* Interface for functions run at rendezvous points
**/
public interface RendezvousFunction {
/**
* Perform some function on the objects presented at
* a rendezvous. The objects array holds all presented
* items; one per thread. Its length is the number of parties.
* The array is ordered by arrival into the rendezvous.
* So, the last element (at objects[objects.length-1])
* is guaranteed to have been presented by the thread performing
* this function. No identifying information is
* otherwise kept about which thread presented which item.
* If you need to
* trace origins, you will need to use an item type for rendezvous
* that includes identifying information. After return of this
* function, other threads are released, and each returns with
* the item with the same index as the one it presented.
**/
public void rendezvousFunction(Object[] objects);
}
/**
* The default rendezvous function. Rotates the array
* so that each thread returns an item presented by some
* other thread (or itself, if parties is 1).
**/
public static class Rotator implements RendezvousFunction {
/** Rotate the array **/
public void rendezvousFunction(Object[] objects) {
int lastIdx = objects.length - 1;
Object first = objects[0];
for (int i = 0; i < lastIdx; ++i) objects[i] = objects[i+1];
objects[lastIdx] = first;
}
}
protected final int parties_;
protected boolean broken_ = false;
/**
* Number of threads that have entered rendezvous
**/
protected int entries_ = 0;
/**
* Number of threads that are permitted to depart rendezvous
**/
protected long departures_ = 0;
/**
* Incoming threads pile up on entry until last set done.
**/
protected final Semaphore entryGate_;
/**
* Temporary holder for items in exchange
**/
protected final Object[] slots_;
/**
* The function to run at rendezvous point
**/
protected RendezvousFunction rendezvousFunction_;
/**
* Create a Barrier for the indicated number of parties,
* and the default Rotator function to run at each barrier point.
* @exception IllegalArgumentException if parties less than or equal to zero.
**/
public Rendezvous(int parties) {
this(parties, new Rotator());
}
/**
* Create a Barrier for the indicated number of parties.
* and the given function to run at each barrier point.
* @exception IllegalArgumentException if parties less than or equal to zero.
**/
public Rendezvous(int parties, RendezvousFunction function) {
if (parties <= 0) throw new IllegalArgumentException();
parties_ = parties;
rendezvousFunction_ = function;
entryGate_ = new WaiterPreferenceSemaphore(parties);
slots_ = new Object[parties];
}
/**
* Set the function to call at the point at which all threads reach the
* rendezvous. This function is run exactly once, by the thread
* that trips the barrier. The function is not run if the barrier is
* broken.
* @param function the function to run. If null, no function is run.
* @return the previous function
**/
public synchronized RendezvousFunction setRendezvousFunction(RendezvousFunction function) {
RendezvousFunction old = rendezvousFunction_;
rendezvousFunction_ = function;
return old;
}
public int parties() { return parties_; }
public synchronized boolean broken() { return broken_; }
/**
* Reset to initial state. Clears both the broken status
* and any record of waiting threads, and releases all
* currently waiting threads with indeterminate return status.
* This method is intended only for use in recovery actions
* in which it is somehow known
* that no thread could possibly be relying on the
* the synchronization properties of this barrier.
**/
public void restart() {
// This is not very good, but probably the best that can be done
for (;;) {
synchronized(this) {
if (entries_ != 0) {
notifyAll();
}
else {
broken_ = false;
return;
}
}
Thread.yield();
}
}
/**
* Enter a rendezvous; returning after all other parties arrive.
* @param x the item to present at rendezvous point.
* By default, this item is exchanged with another.
* @return an item x given by some thread, and/or processed
* by the rendezvousFunction.
* @exception BrokenBarrierException
* if any other thread
* in any previous or current barrier
* since either creation or the last
* The class currently uses a standard array-based heap, as described
* in, for example, Sedgewick's Algorithms text. All methods
* are fully synchronized. In the future,
* it may instead use structures permitting finer-grained locking.
* [ Introduction to this package. ]
**/
public class Heap {
protected Object[] nodes_; // the tree nodes, packed into an array
protected int count_ = 0; // number of used slots
protected final Comparator cmp_; // for ordering
/**
* Create a Heap with the given initial capacity and comparator
* @exception IllegalArgumentException if capacity less or equal to zero
**/
public Heap(int capacity, Comparator cmp)
throws IllegalArgumentException {
if (capacity <= 0) throw new IllegalArgumentException();
nodes_ = new Object[capacity];
cmp_ = cmp;
}
/**
* Create a Heap with the given capacity,
* and relying on natural ordering.
**/
public Heap(int capacity) {
this(capacity, null);
}
/** perform element comaprisons using comparator or natural ordering **/
protected int compare(Object a, Object b) {
if (cmp_ == null)
return ((Comparable)a).compareTo(b);
else
return cmp_.compare(a, b);
}
// indexes of heap parents and children
protected final int parent(int k) { return (k - 1) / 2; }
protected final int left(int k) { return 2 * k + 1; }
protected final int right(int k) { return 2 * (k + 1); }
/**
* insert an element, resize if necessary
**/
public synchronized void insert(Object x) {
if (count_ >= nodes_.length) {
int newcap = 3 * nodes_.length / 2 + 1;
Object[] newnodes = new Object[newcap];
System.arraycopy(nodes_, 0, newnodes, 0, nodes_.length);
nodes_ = newnodes;
}
int k = count_;
++count_;
while (k > 0) {
int par = parent(k);
if (compare(x, nodes_[par]) < 0) {
nodes_[k] = nodes_[par];
k = par;
}
else break;
}
nodes_[k] = x;
}
/**
* Return and remove least element, or null if empty
**/
public synchronized Object extract() {
if (count_ < 1) return null;
int k = 0; // take element at root;
Object least = nodes_[k];
--count_;
Object x = nodes_[count_];
nodes_[count_] = null;
for (;;) {
int l = left(k);
if (l >= count_)
break;
else {
int r = right(k);
int child = (r >= count_ || compare(nodes_[l], nodes_[r]) < 0)? l : r;
if (compare(x, nodes_[child]) > 0) {
nodes_[k] = nodes_[child];
k = child;
}
else break;
}
}
nodes_[k] = x;
return least;
}
/** Return least element without removing it, or null if empty **/
public synchronized Object peek() {
if (count_ > 0)
return nodes_[0];
else
return null;
}
/** Return number of elements **/
public synchronized int size() {
return count_;
}
/** remove all elements **/
public synchronized void clear() {
for (int i = 0; i < count_; ++i)
nodes_[i] = null;
count_ = 0;
}
}
concurrent-dfsg-1.3.4/WaitableLong.java 0000644 0001750 0001750 00000012173 10202157355 020263 0 ustar wbaer wbaer 0000000 0000000 /*
File: WaitableLong.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
23Jun1998 dl Create public version
13may2004 dl Add notifying bit ops
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading waiting and signalling operations
* on single long variables.
*
* [ Introduction to this package. ]
**/
public class WaitableLong extends SynchronizedLong {
/**
* Make a new WaitableLong with the given initial value,
* and using its own internal lock.
**/
public WaitableLong(long initialValue) {
super(initialValue);
}
/**
* Make a new WaitableLong with the given initial value,
* and using the supplied lock.
**/
public WaitableLong(long initialValue, Object lock) {
super(initialValue, lock);
}
public long set(long newValue) {
synchronized (lock_) {
lock_.notifyAll();
return super.set(newValue);
}
}
public boolean commit(long assumedValue, long newValue) {
synchronized (lock_) {
boolean success = super.commit(assumedValue, newValue);
if (success) lock_.notifyAll();
return success;
}
}
public long increment() {
synchronized (lock_) {
lock_.notifyAll();
return super.increment();
}
}
public long decrement() {
synchronized (lock_) {
lock_.notifyAll();
return super.decrement();
}
}
public long add(long amount) {
synchronized (lock_) {
lock_.notifyAll();
return super.add(amount);
}
}
public long subtract(long amount) {
synchronized (lock_) {
lock_.notifyAll();
return super.subtract(amount);
}
}
public long multiply(long factor) {
synchronized (lock_) {
lock_.notifyAll();
return super.multiply(factor);
}
}
public long divide(long factor) {
synchronized (lock_) {
lock_.notifyAll();
return super.divide(factor);
}
}
/**
* Set the value to its complement
* @return the new value
**/
public long complement() {
synchronized (lock_) {
value_ = ~value_;
lock_.notifyAll();
return value_;
}
}
/**
* Set value to value & b.
* @return the new value
**/
public long and(long b) {
synchronized (lock_) {
value_ = value_ & b;
lock_.notifyAll();
return value_;
}
}
/**
* Set value to value | b.
* @return the new value
**/
public long or(long b) {
synchronized (lock_) {
value_ = value_ | b;
lock_.notifyAll();
return value_;
}
}
/**
* Set value to value ^ b.
* @return the new value
**/
public long xor(long b) {
synchronized (lock_) {
value_ = value_ ^ b;
lock_.notifyAll();
return value_;
}
}
/**
* Wait until value equals c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenEqual(long c, Runnable action) throws InterruptedException {
synchronized(lock_) {
while (!(value_ == c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value not equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenNotEqual(long c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ != c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value less than or equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenLessEqual(long c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ <= c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value less than c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenLess(long c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ < c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value greater than or equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenGreaterEqual(long c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ >= c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value greater than c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenGreater(long c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ > c)) lock_.wait();
if (action != null) action.run();
}
}
}
concurrent-dfsg-1.3.4/ThreadFactoryUser.java 0000644 0001750 0001750 00000003326 10202157355 021311 0 ustar wbaer wbaer 0000000 0000000 /*
File: ThreadFactoryUser.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
28aug1998 dl refactored from Executor classes
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
*
* Base class for Executors and related classes that rely on thread factories.
* Generally intended to be used as a mixin-style abstract class, but
* can also be used stand-alone.
* [ Introduction to this package. ]
**/
public class ThreadFactoryUser {
protected ThreadFactory threadFactory_ = new DefaultThreadFactory();
protected static class DefaultThreadFactory implements ThreadFactory {
public Thread newThread(Runnable command) {
return new Thread(command);
}
}
/**
* Set the factory for creating new threads.
* By default, new threads are created without any special priority,
* threadgroup, or status parameters.
* You can use a different factory
* to change the kind of Thread class used or its construction
* parameters.
* @param factory the factory to use
* @return the previous factory
**/
public synchronized ThreadFactory setThreadFactory(ThreadFactory factory) {
ThreadFactory old = threadFactory_;
threadFactory_ = factory;
return old;
}
/**
* Get the factory for creating new threads.
**/
public synchronized ThreadFactory getThreadFactory() {
return threadFactory_;
}
}
concurrent-dfsg-1.3.4/SyncList.java 0000644 0001750 0001750 00000015757 10202157355 017476 0 ustar wbaer wbaer 0000000 0000000 /*
File: SyncList.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
1Aug1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.util.*;
/**
* SyncLists wrap Sync-based control around java.util.Lists.
* They support the following additional reader operations over
* SyncCollection: hashCode, equals, get, indexOf, lastIndexOf,
* subList. They support additional writer operations remove(int),
* set(int), add(int), addAll(int). The corresponding listIterators
* and are similarly extended.
* [ Introduction to this package. ]
* @see SyncCollection
**/
public class SyncList extends SyncCollection implements List {
/**
* Create a new SyncList protecting the given collection,
* and using the given sync to control both reader and writer methods.
* Common, reasonable choices for the sync argument include
* Mutex, ReentrantLock, and Semaphores initialized to 1.
**/
public SyncList(List list, Sync sync) {
super (list, sync);
}
/**
* Create a new SyncList protecting the given list,
* and using the given ReadWriteLock to control reader and writer methods.
**/
public SyncList(List list, ReadWriteLock rwl) {
super (list, rwl.readLock(), rwl.writeLock());
}
/**
* Create a new SyncList protecting the given list,
* and using the given pair of locks to control reader and writer methods.
**/
public SyncList(List list, Sync readLock, Sync writeLock) {
super(list, readLock, writeLock);
}
protected List baseList() {
return (List)c_;
}
public int hashCode() {
boolean wasInterrupted = beforeRead();
try {
return c_.hashCode();
}
finally {
afterRead(wasInterrupted);
}
}
public boolean equals(Object o) {
boolean wasInterrupted = beforeRead();
try {
return c_.equals(o);
}
finally {
afterRead(wasInterrupted);
}
}
public Object get(int index) {
boolean wasInterrupted = beforeRead();
try {
return baseList().get(index);
}
finally {
afterRead(wasInterrupted);
}
}
public int indexOf(Object o) {
boolean wasInterrupted = beforeRead();
try {
return baseList().indexOf(o);
}
finally {
afterRead(wasInterrupted);
}
}
public int lastIndexOf(Object o) {
boolean wasInterrupted = beforeRead();
try {
return baseList().lastIndexOf(o);
}
finally {
afterRead(wasInterrupted);
}
}
public List subList(int fromIndex, int toIndex) {
boolean wasInterrupted = beforeRead();
try {
return new SyncList(baseList().subList(fromIndex, toIndex), rd_, wr_);
}
finally {
afterRead(wasInterrupted);
}
}
public Object set(int index, Object o) {
try {
wr_.acquire();
try {
return baseList().set(index, o);
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
public Object remove(int index) {
try {
wr_.acquire();
try {
return baseList().remove(index);
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
public void add(int index, Object o) {
try {
wr_.acquire();
try {
baseList().add(index, o);
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
public boolean addAll(int index, Collection coll) {
try {
wr_.acquire();
try {
return baseList().addAll(index, coll);
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
public ListIterator unprotectedListIterator() {
boolean wasInterrupted = beforeRead();
try {
return baseList().listIterator();
}
finally {
afterRead(wasInterrupted);
}
}
public ListIterator listIterator() {
boolean wasInterrupted = beforeRead();
try {
return new SyncCollectionListIterator(baseList().listIterator());
}
finally {
afterRead(wasInterrupted);
}
}
public ListIterator unprotectedListIterator(int index) {
boolean wasInterrupted = beforeRead();
try {
return baseList().listIterator(index);
}
finally {
afterRead(wasInterrupted);
}
}
public ListIterator listIterator(int index) {
boolean wasInterrupted = beforeRead();
try {
return new SyncCollectionListIterator(baseList().listIterator(index));
}
finally {
afterRead(wasInterrupted);
}
}
public class SyncCollectionListIterator extends SyncCollectionIterator implements ListIterator {
SyncCollectionListIterator(Iterator baseIterator) {
super(baseIterator);
}
protected ListIterator baseListIterator() {
return (ListIterator)(baseIterator_);
}
public boolean hasPrevious() {
boolean wasInterrupted = beforeRead();
try {
return baseListIterator().hasPrevious();
}
finally {
afterRead(wasInterrupted);
}
}
public Object previous() {
boolean wasInterrupted = beforeRead();
try {
return baseListIterator().previous();
}
finally {
afterRead(wasInterrupted);
}
}
public int nextIndex() {
boolean wasInterrupted = beforeRead();
try {
return baseListIterator().nextIndex();
}
finally {
afterRead(wasInterrupted);
}
}
public int previousIndex() {
boolean wasInterrupted = beforeRead();
try {
return baseListIterator().previousIndex();
}
finally {
afterRead(wasInterrupted);
}
}
public void set(Object o) {
try {
wr_.acquire();
try {
baseListIterator().set(o);
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
public void add(Object o) {
try {
wr_.acquire();
try {
baseListIterator().add(o);
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
}
}
concurrent-dfsg-1.3.4/Executor.java 0000644 0001750 0001750 00000005044 10202157355 017510 0 ustar wbaer wbaer 0000000 0000000 /*
File: Executor.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
19Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* Interface for objects that execute Runnables,
* as well as various objects that can be wrapped
* as Runnables.
* The main reason to use Executor throughout a program or
* subsystem is to provide flexibility: You can easily
* change from using thread-per-task to using pools or
* queuing, without needing to change most of your code that
* generates tasks.
*
* The general intent is that execution be asynchronous,
* or at least independent of the caller. For example,
* one of the simplest implementations of
*
* [ Introduction to this package. ]
**/
public interface Executor {
/**
* Execute the given command. This method is guaranteed
* only to arrange for execution, that may actually
* occur sometime later; for example in a new
* thread. However, in fully generic use, callers
* should be prepared for execution to occur in
* any fashion at all, including immediate direct
* execution.
*
* The method is defined not to throw
* any checked exceptions during execution of the command. Generally,
* any problems encountered will be asynchronous and
* so must be dealt with via callbacks or error handler
* objects. If necessary, any context-dependent
* catastrophic errors encountered during
* actions that arrange for execution could be accompanied
* by throwing context-dependent unchecked exceptions.
*
* However, the method does throw InterruptedException:
* It will fail to arrange for execution
* if the current thread is currently interrupted.
* Further, the general contract of the method is to avoid,
* suppress, or abort execution if interruption is detected
* in any controllable context surrounding execution.
**/
public void execute(Runnable command) throws InterruptedException;
}
concurrent-dfsg-1.3.4/SyncMap.java 0000644 0001750 0001750 00000014405 10202157355 017265 0 ustar wbaer wbaer 0000000 0000000 /*
File: SyncMap.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
1Aug1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.util.*;
/**
* SyncMaps wrap Sync-based control around java.util.Maps.
* They operate in the same way as SyncCollection.
*
* Reader operations are
* [ Introduction to this package. ]
* @see SyncCollection
**/
public class SyncMap implements Map {
protected final Map c_; // Backing Map
protected final Sync rd_; // sync for read-only methods
protected final Sync wr_; // sync for mutative methods
protected final SynchronizedLong syncFailures_ = new SynchronizedLong(0);
/**
* Create a new SyncMap protecting the given map,
* and using the given sync to control both reader and writer methods.
* Common, reasonable choices for the sync argument include
* Mutex, ReentrantLock, and Semaphores initialized to 1.
**/
public SyncMap(Map map, Sync sync) {
this (map, sync, sync);
}
/**
* Create a new SyncMap protecting the given map,
* and using the given ReadWriteLock to control reader and writer methods.
**/
public SyncMap(Map map, ReadWriteLock rwl) {
this (map, rwl.readLock(), rwl.writeLock());
}
/**
* Create a new SyncMap protecting the given map,
* and using the given pair of locks to control reader and writer methods.
**/
public SyncMap(Map map, Sync readLock, Sync writeLock) {
c_ = map;
rd_ = readLock;
wr_ = writeLock;
}
/**
* Return the Sync object managing read-only operations
**/
public Sync readerSync() {
return rd_;
}
/**
* Return the Sync object managing mutative operations
**/
public Sync writerSync() {
return wr_;
}
/**
* Return the number of synchronization failures for read-only operations
**/
public long syncFailures() {
return syncFailures_.get();
}
/** Try to acquire sync before a reader operation; record failure **/
protected boolean beforeRead() {
try {
rd_.acquire();
return false;
}
catch (InterruptedException ex) {
syncFailures_.increment();
return true;
}
}
/** Clean up after a reader operation **/
protected void afterRead(boolean wasInterrupted) {
if (wasInterrupted) {
Thread.currentThread().interrupt();
}
else
rd_.release();
}
public int hashCode() {
boolean wasInterrupted = beforeRead();
try {
return c_.hashCode();
}
finally {
afterRead(wasInterrupted);
}
}
public boolean equals(Object o) {
boolean wasInterrupted = beforeRead();
try {
return c_.equals(o);
}
finally {
afterRead(wasInterrupted);
}
}
public int size() {
boolean wasInterrupted = beforeRead();
try {
return c_.size();
}
finally {
afterRead(wasInterrupted);
}
}
public boolean isEmpty() {
boolean wasInterrupted = beforeRead();
try {
return c_.isEmpty();
}
finally {
afterRead(wasInterrupted);
}
}
public boolean containsKey(Object o) {
boolean wasInterrupted = beforeRead();
try {
return c_.containsKey(o);
}
finally {
afterRead(wasInterrupted);
}
}
public boolean containsValue(Object o) {
boolean wasInterrupted = beforeRead();
try {
return c_.containsValue(o);
}
finally {
afterRead(wasInterrupted);
}
}
public Object get(Object key) {
boolean wasInterrupted = beforeRead();
try {
return c_.get(key);
}
finally {
afterRead(wasInterrupted);
}
}
public Object put(Object key, Object value) {
try {
wr_.acquire();
try {
return c_.put(key, value);
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
public Object remove(Object key) {
try {
wr_.acquire();
try {
return c_.remove(key);
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
public void putAll(Map coll) {
try {
wr_.acquire();
try {
c_.putAll(coll);
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
public void clear() {
try {
wr_.acquire();
try {
c_.clear();
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
private transient Set keySet_ = null;
private transient Set entrySet_ = null;
private transient Collection values_ = null;
public Set keySet() {
boolean wasInterrupted = beforeRead();
try {
if (keySet_ == null)
keySet_ = new SyncSet(c_.keySet(), rd_, wr_);
return keySet_;
}
finally {
afterRead(wasInterrupted);
}
}
public Set entrySet() {
boolean wasInterrupted = beforeRead();
try {
if (entrySet_ == null)
entrySet_ = new SyncSet(c_.entrySet(), rd_, wr_);
return entrySet_;
}
finally {
afterRead(wasInterrupted);
}
}
public Collection values() {
boolean wasInterrupted = beforeRead();
try {
if (values_ == null)
values_ = new SyncCollection(c_.values(), rd_, wr_);
return values_;
}
finally {
afterRead(wasInterrupted);
}
}
}
concurrent-dfsg-1.3.4/WaitableInt.java 0000644 0001750 0001750 00000012126 10202157355 020114 0 ustar wbaer wbaer 0000000 0000000 /*
File: WaitableInt.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
23Jun1998 dl Create public version
13may2004 dl Add notifying bit ops
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading waiting and signalling operations
* on single int variables.
*
* [ Introduction to this package. ]
**/
public class WaitableInt extends SynchronizedInt {
/**
* Make a new WaitableInt with the given initial value,
* and using its own internal lock.
**/
public WaitableInt(int initialValue) {
super(initialValue);
}
/**
* Make a new WaitableInt with the given initial value,
* and using the supplied lock.
**/
public WaitableInt(int initialValue, Object lock) {
super(initialValue, lock);
}
public int set(int newValue) {
synchronized (lock_) {
lock_.notifyAll();
return super.set(newValue);
}
}
public boolean commit(int assumedValue, int newValue) {
synchronized (lock_) {
boolean success = super.commit(assumedValue, newValue);
if (success) lock_.notifyAll();
return success;
}
}
public int increment() {
synchronized (lock_) {
lock_.notifyAll();
return super.increment();
}
}
public int decrement() {
synchronized (lock_) {
lock_.notifyAll();
return super.decrement();
}
}
public int add(int amount) {
synchronized (lock_) {
lock_.notifyAll();
return super.add(amount);
}
}
public int subtract(int amount) {
synchronized (lock_) {
lock_.notifyAll();
return super.subtract(amount);
}
}
public int multiply(int factor) {
synchronized (lock_) {
lock_.notifyAll();
return super.multiply(factor);
}
}
public int divide(int factor) {
synchronized (lock_) {
lock_.notifyAll();
return super.divide(factor);
}
}
/**
* Set the value to its complement
* @return the new value
**/
public int complement() {
synchronized (lock_) {
value_ = ~value_;
lock_.notifyAll();
return value_;
}
}
/**
* Set value to value & b.
* @return the new value
**/
public int and(int b) {
synchronized (lock_) {
value_ = value_ & b;
lock_.notifyAll();
return value_;
}
}
/**
* Set value to value | b.
* @return the new value
**/
public int or(int b) {
synchronized (lock_) {
value_ = value_ | b;
lock_.notifyAll();
return value_;
}
}
/**
* Set value to value ^ b.
* @return the new value
**/
public int xor(int b) {
synchronized (lock_) {
value_ = value_ ^ b;
lock_.notifyAll();
return value_;
}
}
/**
* Wait until value equals c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenEqual(int c, Runnable action) throws InterruptedException {
synchronized(lock_) {
while (!(value_ == c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value not equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenNotEqual(int c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ != c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value less than or equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenLessEqual(int c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ <= c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value less than c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenLess(int c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ < c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value greater than or equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenGreaterEqual(int c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ >= c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value greater than c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenGreater(int c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ > c)) lock_.wait();
if (action != null) action.run();
}
}
}
concurrent-dfsg-1.3.4/Sync.java 0000644 0001750 0001750 00000025466 10202157355 016640 0 ustar wbaer wbaer 0000000 0000000 /*
File: Sync.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
5Aug1998 dl Added some convenient time constants
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* Main interface for locks, gates, and conditions.
*
* Sync objects isolate waiting and notification for particular
* logical states, resource availability, events, and the like that are
* shared across multiple threads. Use of Syncs sometimes
* (but by no means always) adds flexibility and efficiency
* compared to the use of plain java monitor methods
* and locking, and are sometimes (but by no means always)
* simpler to program with.
*
*
* Most Syncs are intended to be used primarily (although
* not exclusively) in before/after constructions such as:
*
* One reason to bother with such constructions is to use deadlock-
* avoiding back-offs when dealing with locks involving multiple objects.
* For example, here is a Cell class that uses attempt to back-off
* and retry if two Cells are trying to swap values with each other
* at the same time.
*
* Here is an even fancier version, that uses lock re-ordering
* upon conflict:
*
* Interruptions are in general handled as early as possible.
* Normally, InterruptionExceptions are thrown
* in acquire and attempt(msec) if interruption
* is detected upon entry to the method, as well as in any
* later context surrounding waits.
* However, interruption status is ignored in release();
*
* Timed versions of attempt report failure via return value.
* If so desired, you can transform such constructions to use exception
* throws via
*
* The TimoutSync wrapper class can be used to automate such usages.
*
* All time values are expressed in milliseconds as longs, which have a maximum
* value of Long.MAX_VALUE, or almost 300,000 centuries. It is not
* known whether JVMs actually deal correctly with such extreme values.
* For convenience, some useful time values are defined as static constants.
*
* All implementations of the three Sync methods guarantee to
* somehow employ Java
* Syncs may also be used in spinlock constructions. Although
* it is normally best to just use acquire(), various forms
* of busy waits can be implemented. For a simple example
* (but one that would probably never be preferable to using acquire()):
*
* In addition pure synchronization control, Syncs
* may be useful in any context requiring before/after methods.
* For example, you can use an ObservableSync
* (perhaps as part of a LayeredSync) in order to obtain callbacks
* before and after each method invocation for a given class.
*
* [ Introduction to this package. ]
**/
public interface Sync {
/**
* Wait (possibly forever) until successful passage.
* Fail only upon interuption. Interruptions always result in
* `clean' failures. On failure, you can be sure that it has not
* been acquired, and that no
* corresponding release should be performed. Conversely,
* a normal return guarantees that the acquire was successful.
**/
public void acquire() throws InterruptedException;
/**
* Wait at most msecs to pass; report whether passed.
*
* The method has best-effort semantics:
* The msecs bound cannot
* be guaranteed to be a precise upper bound on wait time in Java.
* Implementations generally can only attempt to return as soon as possible
* after the specified bound. Also, timers in Java do not stop during garbage
* collection, so timeouts can occur just because a GC intervened.
* So, msecs arguments should be used in
* a coarse-grained manner. Further,
* implementations cannot always guarantee that this method
* will return at all without blocking indefinitely when used in
* unintended ways. For example, deadlocks may be encountered
* when called in an unintended context.
*
* @param msecs the number of milleseconds to wait.
* An argument less than or equal to zero means not to wait at all.
* However, this may still require
* access to a synchronization lock, which can impose unbounded
* delay if there is a lot of contention among threads.
* @return true if acquired
**/
public boolean attempt(long msecs) throws InterruptedException;
/**
* Potentially enable others to pass.
*
* Because release does not raise exceptions,
* it can be used in `finally' clauses without requiring extra
* embedded try/catch blocks. But keep in mind that
* as with any java method, implementations may
* still throw unchecked exceptions such as Error or NullPointerException
* when faced with uncontinuable errors. However, these should normally
* only be caught by higher-level error handlers.
**/
public void release();
/** One second, in milliseconds; convenient as a time-out value **/
public static final long ONE_SECOND = 1000;
/** One minute, in milliseconds; convenient as a time-out value **/
public static final long ONE_MINUTE = 60 * ONE_SECOND;
/** One hour, in milliseconds; convenient as a time-out value **/
public static final long ONE_HOUR = 60 * ONE_MINUTE;
/** One day, in milliseconds; convenient as a time-out value **/
public static final long ONE_DAY = 24 * ONE_HOUR;
/** One week, in milliseconds; convenient as a time-out value **/
public static final long ONE_WEEK = 7 * ONE_DAY;
/** One year in milliseconds; convenient as a time-out value **/
// Not that it matters, but there is some variation across
// standard sources about value at msec precision.
// The value used is the same as in java.util.GregorianCalendar
public static final long ONE_YEAR = (long)(365.2425 * ONE_DAY);
/** One century in milliseconds; convenient as a time-out value **/
public static final long ONE_CENTURY = 100 * ONE_YEAR;
}
concurrent-dfsg-1.3.4/ReadWriteLock.java 0000644 0001750 0001750 00000004552 10202157355 020414 0 ustar wbaer wbaer 0000000 0000000 /*
File: ReadWriteLock.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* ReadWriteLocks maintain a pair of associated locks.
* The readLock may be held simultanously by multiple
* reader threads, so long as there are no writers. The writeLock
* is exclusive. ReadWrite locks are generally preferable to
* plain Sync locks or synchronized methods in cases where:
*
* Standard usage:
* [ Introduction to this package. ]
**/
public interface ReadWriteLock {
/** get the readLock **/
Sync readLock();
/** get the writeLock **/
Sync writeLock();
}
concurrent-dfsg-1.3.4/BoundedLinkedQueue.java 0000644 0001750 0001750 00000023657 10202157355 021440 0 ustar wbaer wbaer 0000000 0000000 /*
File: BoundedLinkedQueue.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
17Jul1998 dl Simplified by eliminating wait counts
25aug1998 dl added peek
10oct1999 dl lock on node object to ensure visibility
27jan2000 dl setCapacity forces immediate permit reconcile
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A bounded variant of
* LinkedQueue
* class. This class may be
* preferable to
* BoundedBuffer
* because it allows a bit more
* concurency among puts and takes, because it does not
* pre-allocate fixed storage for elements, and allows
* capacity to be dynamically reset.
* On the other hand, since it allocates a node object
* on each put, it can be slow on systems with slow
* allocation and GC.
* Also, it may be
* preferable to
* LinkedQueue
* when you need to limit
* the capacity to prevent resource exhaustion. This protection
* normally does not hurt much performance-wise: When the
* queue is not empty or full, most puts and
* takes are still usually able to execute concurrently.
* @see LinkedQueue
* @see BoundedBuffer
* [ Introduction to this package. ]
**/
public class BoundedLinkedQueue implements BoundedChannel {
/*
* It might be a bit nicer if this were declared as
* a subclass of LinkedQueue, or a sibling class of
* a common abstract class. It shares much of the
* basic design and bookkeeping fields. But too
* many details differ to make this worth doing.
*/
/**
* Dummy header node of list. The first actual node, if it exists, is always
* at head_.next. After each take, the old first node becomes the head.
**/
protected LinkedNode head_;
/**
* The last node of list. Put() appends to list, so modifies last_
**/
protected LinkedNode last_;
/**
* Helper monitor. Ensures that only one put at a time executes.
**/
protected final Object putGuard_ = new Object();
/**
* Helper monitor. Protects and provides wait queue for takes
**/
protected final Object takeGuard_ = new Object();
/** Number of elements allowed **/
protected int capacity_;
/**
* One side of a split permit count.
* The counts represent permits to do a put. (The queue is full when zero).
* Invariant: putSidePutPermits_ + takeSidePutPermits_ = capacity_ - length.
* (The length is never separately recorded, so this cannot be
* checked explicitly.)
* To minimize contention between puts and takes, the
* put side uses up all of its permits before transfering them from
* the take side. The take side just increments the count upon each take.
* Thus, most puts and take can run independently of each other unless
* the queue is empty or full.
* Initial value is queue capacity.
**/
protected int putSidePutPermits_;
/** Number of takes since last reconcile **/
protected int takeSidePutPermits_ = 0;
/**
* Create a queue with the given capacity
* @exception IllegalArgumentException if capacity less or equal to zero
**/
public BoundedLinkedQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
capacity_ = capacity;
putSidePutPermits_ = capacity;
head_ = new LinkedNode(null);
last_ = head_;
}
/**
* Create a queue with the current default capacity
**/
public BoundedLinkedQueue() {
this(DefaultChannelCapacity.get());
}
/**
* Move put permits from take side to put side;
* return the number of put side permits that are available.
* Call only under synch on puGuard_ AND this.
**/
protected final int reconcilePutPermits() {
putSidePutPermits_ += takeSidePutPermits_;
takeSidePutPermits_ = 0;
return putSidePutPermits_;
}
/** Return the current capacity of this queue **/
public synchronized int capacity() { return capacity_; }
/**
* Return the number of elements in the queue.
* This is only a snapshot value, that may be in the midst
* of changing. The returned value will be unreliable in the presence of
* active puts and takes, and should only be used as a heuristic
* estimate, for example for resource monitoring purposes.
**/
public synchronized int size() {
/*
This should ideally synch on putGuard_, but
doing so would cause it to block waiting for an in-progress
put, which might be stuck. So we instead use whatever
value of putSidePutPermits_ that we happen to read.
*/
return capacity_ - (takeSidePutPermits_ + putSidePutPermits_);
}
/**
* Reset the capacity of this queue.
* If the new capacity is less than the old capacity,
* existing elements are NOT removed, but
* incoming puts will not proceed until the number of elements
* is less than the new capacity.
* @exception IllegalArgumentException if capacity less or equal to zero
**/
public void setCapacity(int newCapacity) {
if (newCapacity <= 0) throw new IllegalArgumentException();
synchronized (putGuard_) {
synchronized(this) {
takeSidePutPermits_ += (newCapacity - capacity_);
capacity_ = newCapacity;
// Force immediate reconcilation.
reconcilePutPermits();
notifyAll();
}
}
}
/** Main mechanics for take/poll **/
protected synchronized Object extract() {
synchronized(head_) {
Object x = null;
LinkedNode first = head_.next;
if (first != null) {
x = first.value;
first.value = null;
head_ = first;
++takeSidePutPermits_;
notify();
}
return x;
}
}
public Object peek() {
synchronized(head_) {
LinkedNode first = head_.next;
if (first != null)
return first.value;
else
return null;
}
}
public Object take() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
Object x = extract();
if (x != null)
return x;
else {
synchronized(takeGuard_) {
try {
for (;;) {
x = extract();
if (x != null) {
return x;
}
else {
takeGuard_.wait();
}
}
}
catch(InterruptedException ex) {
takeGuard_.notify();
throw ex;
}
}
}
}
public Object poll(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
Object x = extract();
if (x != null)
return x;
else {
synchronized(takeGuard_) {
try {
long waitTime = msecs;
long start = (msecs <= 0)? 0: System.currentTimeMillis();
for (;;) {
x = extract();
if (x != null || waitTime <= 0) {
return x;
}
else {
takeGuard_.wait(waitTime);
waitTime = msecs - (System.currentTimeMillis() - start);
}
}
}
catch(InterruptedException ex) {
takeGuard_.notify();
throw ex;
}
}
}
}
/** Notify a waiting take if needed **/
protected final void allowTake() {
synchronized(takeGuard_) {
takeGuard_.notify();
}
}
/**
* Create and insert a node.
* Call only under synch on putGuard_
**/
protected void insert(Object x) {
--putSidePutPermits_;
LinkedNode p = new LinkedNode(x);
synchronized(last_) {
last_.next = p;
last_ = p;
}
}
/*
put and offer(ms) differ only in policy before insert/allowTake
*/
public void put(Object x) throws InterruptedException {
if (x == null) throw new IllegalArgumentException();
if (Thread.interrupted()) throw new InterruptedException();
synchronized(putGuard_) {
if (putSidePutPermits_ <= 0) { // wait for permit.
synchronized(this) {
if (reconcilePutPermits() <= 0) {
try {
for(;;) {
wait();
if (reconcilePutPermits() > 0) {
break;
}
}
}
catch (InterruptedException ex) {
notify();
throw ex;
}
}
}
}
insert(x);
}
// call outside of lock to loosen put/take coupling
allowTake();
}
public boolean offer(Object x, long msecs) throws InterruptedException {
if (x == null) throw new IllegalArgumentException();
if (Thread.interrupted()) throw new InterruptedException();
synchronized(putGuard_) {
if (putSidePutPermits_ <= 0) {
synchronized(this) {
if (reconcilePutPermits() <= 0) {
if (msecs <= 0)
return false;
else {
try {
long waitTime = msecs;
long start = System.currentTimeMillis();
for(;;) {
wait(waitTime);
if (reconcilePutPermits() > 0) {
break;
}
else {
waitTime = msecs - (System.currentTimeMillis() - start);
if (waitTime <= 0) {
return false;
}
}
}
}
catch (InterruptedException ex) {
notify();
throw ex;
}
}
}
}
}
insert(x);
}
allowTake();
return true;
}
public boolean isEmpty() {
synchronized(head_) {
return head_.next == null;
}
}
}
concurrent-dfsg-1.3.4/FJTaskRunnerGroup.java 0000644 0001750 0001750 00000050023 10202157355 021240 0 ustar wbaer wbaer 0000000 0000000 /*
File: FJTaskRunnerGroup.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
7Jan1999 dl First public release
12Jan1999 dl made getActiveCount public; misc minor cleanup.
14Jan1999 dl Added executeTask
20Jan1999 dl Allow use of priorities; reformat stats
6Feb1999 dl Lazy thread starts
27Apr1999 dl Renamed
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A stripped down analog of a ThreadGroup used for
* establishing and managing FJTaskRunner threads.
* ThreadRunnerGroups serve as the control boundary separating
* the general world of normal threads from the specialized world
* of FJTasks.
*
* By intent, this class does not subclass java.lang.ThreadGroup, and
* does not support most methods found in ThreadGroups, since they
* would make no sense for FJTaskRunner threads. In fact, the class
* does not deal with ThreadGroups at all. If you want to restrict
* a FJTaskRunnerGroup to a particular ThreadGroup, you can create
* it from within that ThreadGroup.
*
* The main contextual parameter for a FJTaskRunnerGroup is
* the group size, established in the constructor.
* Groups must be of a fixed size.
* There is no way to dynamically increase or decrease the number
* of threads in an existing group.
*
* In general, the group size should be equal to the number
* of CPUs on the system. (Unfortunately, there is no portable
* means of automatically detecting the number of CPUs on a JVM, so there is
* no good way to automate defaults.) In principle, when
* FJTasks are used for computation-intensive tasks, having only
* as many threads as CPUs should minimize bookkeeping overhead
* and contention, and so maximize throughput. However, because
* FJTaskRunners lie atop Java threads, and in turn operating system
* thread support and scheduling policies,
* it is very possible that using more threads
* than CPUs will improve overall throughput even though it adds
* to overhead. This will always be so if FJTasks are I/O bound.
* So it may pay to experiment a bit when tuning on particular platforms.
* You can also use
* In any case, overestimating group sizes never
* seriously degrades performance (at least within reasonable bounds).
* You can also use a value
* less than the number of CPUs in order to reserve processing
* for unrelated threads.
*
* There are two general styles for using a FJTaskRunnerGroup.
* You can create one group per entire program execution, for example
* as a static singleton, and use it for all parallel tasks:
*
* The main supported methods are
* Method [ Introduction to this package. ]
*
* @see FJTask
* @see FJTaskRunner
**/
public class FJTaskRunnerGroup implements Executor {
/** The threads in this group **/
protected final FJTaskRunner[] threads;
/** Group-wide queue for tasks entered via execute() **/
protected final LinkedQueue entryQueue = new LinkedQueue();
/** Number of threads that are not waiting for work **/
protected int activeCount = 0;
/** Number of threads that have been started. Used to avoid
unecessary contention during startup of task sets.
**/
protected int nstarted = 0;
/**
* Compile-time constant. If true, various counts of
* runs, waits, etc., are maintained. These are NOT
* updated with synchronization, so statistics reports
* might not be accurate.
**/
static final boolean COLLECT_STATS = true;
// static final boolean COLLECT_STATS = false;
// for stats
/** The time at which this ThreadRunnerGroup was constructed **/
long initTime = 0;
/** Total number of executes or invokes **/
int entries = 0;
static final int DEFAULT_SCAN_PRIORITY = Thread.MIN_PRIORITY+1;
/**
* Create a FJTaskRunnerGroup with the indicated number
* of FJTaskRunner threads. Normally, the best size to use is
* the number of CPUs on the system.
*
* The threads in a FJTaskRunnerGroup are created with their
* isDaemon status set, so do not normally need to be
* shut down manually upon program termination.
**/
public FJTaskRunnerGroup(int groupSize) {
threads = new FJTaskRunner[groupSize];
initializeThreads();
initTime = System.currentTimeMillis();
}
/**
* Arrange for execution of the given task
* by placing it in a work queue. If the argument
* is not of type FJTask, it is embedded in a FJTask via
*
* Cautions: Some statistics are updated and gathered
* without synchronization,
* so may not be accurate. However, reported counts may be considered
* as lower bounds of actual values.
* Some values may be zero if classes are compiled
* with COLLECT_STATS set to false. (FJTaskRunner and FJTaskRunnerGroup
* classes can be independently compiled with different values of
* COLLECT_STATS.) Also, the counts are maintained as ints so could
* overflow in exceptionally long-lived applications.
*
* These statistics can be useful when tuning algorithms or diagnosing
* problems. For example:
*
* This is not treated as a user-tunable parameter because
* good values do not appear to vary much across JVMs or
* applications. Its main role is to help avoid some
* useless spinning and contention during task startup.
**/
static final long SCANS_PER_SLEEP = 15;
/**
* The maximum time (in msecs) to sleep when a thread is idle,
* yet others are not, so may eventually generate work that
* the current thread can steal. This value reflects the maximum time
* that a thread may sleep when it possibly should not, because there
* are other active threads that might generate work. In practice,
* designs in which some threads become stalled because others
* are running yet not generating tasks are not likely to work
* well in this framework anyway, so the exact value does not matter
* too much. However, keeping it in the sub-second range does
* help smooth out startup and shutdown effects.
**/
static final long MAX_SLEEP_TIME = 100;
/**
* Set active status of thread t to false, and
* then wait until: (a) there is a task in the entry
* queue, or (b) other threads are active, or (c) the current
* thread is interrupted. Upon return, it
* is not certain that there will be work available.
* The thread must itself check.
*
* The main underlying reason
* for these mechanics is that threads do not
* signal each other when they add elements to their queues.
* (This would add to task overhead, reduce locality.
* and increase contention.)
* So we must rely on a tamed form of polling. However, tasks
* inserted into the entry queue do result in signals, so
* tasks can wait on these if all of them are otherwise idle.
**/
protected synchronized void checkActive(FJTaskRunner t, long scans) {
setInactive(t);
try {
// if nothing available, do a hard wait
if (activeCount == 0 && entryQueue.peek() == null) {
wait();
}
else {
// If there is possibly some work,
// sleep for a while before rechecking
long msecs = scans / SCANS_PER_SLEEP;
if (msecs > MAX_SLEEP_TIME) msecs = MAX_SLEEP_TIME;
int nsecs = (msecs == 0) ? 1 : 0; // forces shortest possible sleep
wait(msecs, nsecs);
}
}
catch (InterruptedException ex) {
notify(); // avoid lost notifies on interrupts
Thread.currentThread().interrupt();
}
}
/* ------------ Utility methods ------------- */
/**
* Start or wake up any threads waiting for work
**/
protected synchronized void signalNewTask() {
if (COLLECT_STATS) ++entries;
if (nstarted < threads.length)
threads[nstarted++].start();
else
notify();
}
/**
* Create all FJTaskRunner threads in this group.
**/
protected void initializeThreads() {
for (int i = 0; i < threads.length; ++i) threads[i] = new FJTaskRunner(this);
}
/**
* Wrap wait/notify mechanics around a task so that
* invoke() can wait it out
**/
protected static final class InvokableFJTask extends FJTask {
protected final Runnable wrapped;
protected boolean terminated = false;
protected InvokableFJTask(Runnable r) { wrapped = r; }
public void run() {
try {
if (wrapped instanceof FJTask)
FJTask.invoke((FJTask)(wrapped));
else
wrapped.run();
}
finally {
setTerminated();
}
}
protected synchronized void setTerminated() {
terminated = true;
notifyAll();
}
protected synchronized void awaitTermination() throws InterruptedException {
while (!terminated) wait();
}
}
}
concurrent-dfsg-1.3.4/ThreadedExecutor.java 0000644 0001750 0001750 00000002204 10202157355 021144 0 ustar wbaer wbaer 0000000 0000000 /*
File: ThreadedExecutor.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
21Jun1998 dl Create public version
28aug1998 dl factored out ThreadFactoryUser
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
*
* An implementation of Executor that creates a new
* Thread that invokes the run method of the supplied command.
*
* [ Introduction to this package. ]
**/
public class ThreadedExecutor extends ThreadFactoryUser implements Executor {
/**
* Execute the given command in a new thread.
**/
public synchronized void execute(Runnable command) throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Thread thread = getThreadFactory().newThread(command);
thread.start();
}
}
concurrent-dfsg-1.3.4/SynchronizedInt.java 0000644 0001750 0001750 00000012452 10202157355 021045 0 ustar wbaer wbaer 0000000 0000000 /*
File: SynchronizedInt.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
19Jun1998 dl Create public version
15Apr2003 dl Removed redundant "synchronized" for multiply()
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading synch for int instance variables.
*
* [ Introduction to this package. ]
**/
public class SynchronizedInt extends SynchronizedVariable implements Comparable, Cloneable {
protected int value_;
/**
* Make a new SynchronizedInt with the given initial value,
* and using its own internal lock.
**/
public SynchronizedInt(int initialValue) {
super();
value_ = initialValue;
}
/**
* Make a new SynchronizedInt with the given initial value,
* and using the supplied lock.
**/
public SynchronizedInt(int initialValue, Object lock) {
super(lock);
value_ = initialValue;
}
/**
* Return the current value
**/
public final int get() { synchronized(lock_) { return value_; } }
/**
* Set to newValue.
* @return the old value
**/
public int set(int newValue) {
synchronized (lock_) {
int old = value_;
value_ = newValue;
return old;
}
}
/**
* Set value to newValue only if it is currently assumedValue.
* @return true if successful
**/
public boolean commit(int assumedValue, int newValue) {
synchronized(lock_) {
boolean success = (assumedValue == value_);
if (success) value_ = newValue;
return success;
}
}
/**
* Atomically swap values with another SynchronizedInt.
* Uses identityHashCode to avoid deadlock when
* two SynchronizedInts attempt to simultaneously swap with each other.
* (Note: Ordering via identyHashCode is not strictly guaranteed
* by the language specification to return unique, orderable
* values, but in practice JVMs rely on them being unique.)
* @return the new value
**/
public int swap(SynchronizedInt other) {
if (other == this) return get();
SynchronizedInt fst = this;
SynchronizedInt snd = other;
if (System.identityHashCode(fst) > System.identityHashCode(snd)) {
fst = other;
snd = this;
}
synchronized(fst.lock_) {
synchronized(snd.lock_) {
fst.set(snd.set(fst.get()));
return get();
}
}
}
/**
* Increment the value.
* @return the new value
**/
public int increment() {
synchronized (lock_) {
return ++value_;
}
}
/**
* Decrement the value.
* @return the new value
**/
public int decrement() {
synchronized (lock_) {
return --value_;
}
}
/**
* Add amount to value (i.e., set value += amount)
* @return the new value
**/
public int add(int amount) {
synchronized (lock_) {
return value_ += amount;
}
}
/**
* Subtract amount from value (i.e., set value -= amount)
* @return the new value
**/
public int subtract(int amount) {
synchronized (lock_) {
return value_ -= amount;
}
}
/**
* Multiply value by factor (i.e., set value *= factor)
* @return the new value
**/
public int multiply(int factor) {
synchronized (lock_) {
return value_ *= factor;
}
}
/**
* Divide value by factor (i.e., set value /= factor)
* @return the new value
**/
public int divide(int factor) {
synchronized (lock_) {
return value_ /= factor;
}
}
/**
* Set the value to the negative of its old value
* @return the new value
**/
public int negate() {
synchronized (lock_) {
value_ = -value_;
return value_;
}
}
/**
* Set the value to its complement
* @return the new value
**/
public int complement() {
synchronized (lock_) {
value_ = ~value_;
return value_;
}
}
/**
* Set value to value & b.
* @return the new value
**/
public int and(int b) {
synchronized (lock_) {
value_ = value_ & b;
return value_;
}
}
/**
* Set value to value | b.
* @return the new value
**/
public int or(int b) {
synchronized (lock_) {
value_ = value_ | b;
return value_;
}
}
/**
* Set value to value ^ b.
* @return the new value
**/
public int xor(int b) {
synchronized (lock_) {
value_ = value_ ^ b;
return value_;
}
}
public int compareTo(int other) {
int val = get();
return (val < other)? -1 : (val == other)? 0 : 1;
}
public int compareTo(SynchronizedInt other) {
return compareTo(other.get());
}
public int compareTo(Object other) {
return compareTo((SynchronizedInt)other);
}
public boolean equals(Object other) {
if (other != null &&
other instanceof SynchronizedInt)
return get() == ((SynchronizedInt)other).get();
else
return false;
}
public int hashCode() { return get(); }
public String toString() { return String.valueOf(get()); }
}
concurrent-dfsg-1.3.4/Semaphore.java 0000644 0001750 0001750 00000012461 10202157355 017636 0 ustar wbaer wbaer 0000000 0000000 /*
File: Semaphore.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
5Aug1998 dl replaced int counters with longs
24Aug1999 dl release(n): screen arguments
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* Base class for counting semaphores.
* Conceptually, a semaphore maintains a set of permits.
* Each acquire() blocks if necessary
* until a permit is available, and then takes it.
* Each release adds a permit. However, no actual permit objects
* are used; the Semaphore just keeps a count of the number
* available and acts accordingly.
*
* A semaphore initialized to 1 can serve as a mutual exclusion
* lock.
*
* Different implementation subclasses may provide different
* ordering guarantees (or lack thereof) surrounding which
* threads will be resumed upon a signal.
*
* The default implementation makes NO
* guarantees about the order in which threads will
* acquire permits. It is often faster than other implementations.
*
* Sample usage. Here is a class that uses a semaphore to
* help manage access to a pool of items.
* [ Introduction to this package. ]
**/
public class Semaphore implements Sync {
/** current number of available permits **/
protected long permits_;
/**
* Create a Semaphore with the given initial number of permits.
* Using a seed of one makes the semaphore act as a mutual exclusion lock.
* Negative seeds are also allowed, in which case no acquires will proceed
* until the number of releases has pushed the number of permits past 0.
**/
public Semaphore(long initialPermits) { permits_ = initialPermits; }
/** Wait until a permit is available, and take one **/
public void acquire() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
synchronized(this) {
try {
while (permits_ <= 0) wait();
--permits_;
}
catch (InterruptedException ex) {
notify();
throw ex;
}
}
}
/** Wait at most msecs millisconds for a permit. **/
public boolean attempt(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
synchronized(this) {
if (permits_ > 0) {
--permits_;
return true;
}
else if (msecs <= 0)
return false;
else {
try {
long startTime = System.currentTimeMillis();
long waitTime = msecs;
for (;;) {
wait(waitTime);
if (permits_ > 0) {
--permits_;
return true;
}
else {
waitTime = msecs - (System.currentTimeMillis() - startTime);
if (waitTime <= 0)
return false;
}
}
}
catch(InterruptedException ex) {
notify();
throw ex;
}
}
}
}
/** Release a permit **/
public synchronized void release() {
++permits_;
notify();
}
/**
* Release N permits.
* But may be more efficient in some semaphore implementations.
* @exception IllegalArgumentException if n is negative.
**/
public synchronized void release(long n) {
if (n < 0) throw new IllegalArgumentException("Negative argument");
permits_ += n;
for (long i = 0; i < n; ++i) notify();
}
/**
* Return the current number of available permits.
* Returns an accurate, but possibly unstable value,
* that may change immediately after returning.
**/
public synchronized long permits() {
return permits_;
}
}
concurrent-dfsg-1.3.4/PrioritySemaphore.java 0000644 0001750 0001750 00000005265 10202157355 021404 0 ustar wbaer wbaer 0000000 0000000 /*
File: PrioritySemaphore.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A Semaphore that grants requests to threads with higher
* Thread priority rather than lower priority when there is
* contention. Ordering of requests with the same priority
* is approximately FIFO.
* Priorities are based on Thread.getPriority.
* Changing the priority of an already-waiting thread does NOT
* change its ordering. This class also does not specially deal with priority
* inversion -- when a new high-priority thread enters
* while a low-priority thread is currently running, their
* priorities are not artificially manipulated.
* [ Introduction to this package. ]
**/
public class PrioritySemaphore extends QueuedSemaphore {
/**
* Create a Semaphore with the given initial number of permits.
* Using a seed of one makes the semaphore act as a mutual exclusion lock.
* Negative seeds are also allowed, in which case no acquires will proceed
* until the number of releases has pushed the number of permits past 0.
**/
public PrioritySemaphore(long initialPermits) {
super(new PriorityWaitQueue(), initialPermits);
}
protected static class PriorityWaitQueue extends WaitQueue {
/** An array of wait queues, one per priority **/
protected final FIFOSemaphore.FIFOWaitQueue[] cells_ =
new FIFOSemaphore.FIFOWaitQueue[Thread.MAX_PRIORITY -
Thread.MIN_PRIORITY + 1];
/**
* The index of the highest priority cell that may need to be signalled,
* or -1 if none. Used to minimize array traversal.
**/
protected int maxIndex_ = -1;
protected PriorityWaitQueue() {
for (int i = 0; i < cells_.length; ++i)
cells_[i] = new FIFOSemaphore.FIFOWaitQueue();
}
protected void insert(WaitNode w) {
int idx = Thread.currentThread().getPriority() - Thread.MIN_PRIORITY;
cells_[idx].insert(w);
if (idx > maxIndex_) maxIndex_ = idx;
}
protected WaitNode extract() {
for (;;) {
int idx = maxIndex_;
if (idx < 0)
return null;
WaitNode w = cells_[idx].extract();
if (w != null)
return w;
else
--maxIndex_;
}
}
}
}
concurrent-dfsg-1.3.4/SyncSet.java 0000644 0001750 0001750 00000003744 10202157355 017307 0 ustar wbaer wbaer 0000000 0000000 /*
File: SyncSet.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
1Aug1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.util.*;
/**
* SyncSets wrap Sync-based control around java.util.Sets.
* They support two additional reader operations than do
* SyncCollection: hashCode and equals.
* [ Introduction to this package. ]
* @see SyncCollection
**/
public class SyncSet extends SyncCollection implements Set {
/**
* Create a new SyncSet protecting the given collection,
* and using the given sync to control both reader and writer methods.
* Common, reasonable choices for the sync argument include
* Mutex, ReentrantLock, and Semaphores initialized to 1.
**/
public SyncSet(Set set, Sync sync) {
super (set, sync);
}
/**
* Create a new SyncSet protecting the given set,
* and using the given ReadWriteLock to control reader and writer methods.
**/
public SyncSet(Set set, ReadWriteLock rwl) {
super (set, rwl.readLock(), rwl.writeLock());
}
/**
* Create a new SyncSet protecting the given set,
* and using the given pair of locks to control reader and writer methods.
**/
public SyncSet(Set set, Sync readLock, Sync writeLock) {
super(set, readLock, writeLock);
}
public int hashCode() {
boolean wasInterrupted = beforeRead();
try {
return c_.hashCode();
}
finally {
afterRead(wasInterrupted);
}
}
public boolean equals(Object o) {
boolean wasInterrupted = beforeRead();
try {
return c_.equals(o);
}
finally {
afterRead(wasInterrupted);
}
}
}
concurrent-dfsg-1.3.4/WaitableChar.java 0000644 0001750 0001750 00000007766 10202157355 020255 0 ustar wbaer wbaer 0000000 0000000 /*
File: WaitableChar.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
23Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading waiting and signalling operations
* on single char variables.
*
* [ Introduction to this package. ]
**/
public class WaitableChar extends SynchronizedChar {
/**
* Make a new WaitableChar with the given initial value,
* and using its own internal lock.
**/
public WaitableChar(char initialValue) {
super(initialValue);
}
/**
* Make a new WaitableChar with the given initial value,
* and using the supplied lock.
**/
public WaitableChar(char initialValue, Object lock) {
super(initialValue, lock);
}
public char set(char newValue) {
synchronized (lock_) {
lock_.notifyAll();
return super.set(newValue);
}
}
public boolean commit(char assumedValue, char newValue) {
synchronized (lock_) {
boolean success = super.commit(assumedValue, newValue);
if (success) lock_.notifyAll();
return success;
}
}
public char add(char amount) {
synchronized (lock_) {
lock_.notifyAll();
return super.add(amount);
}
}
public char subtract(char amount) {
synchronized (lock_) {
lock_.notifyAll();
return super.subtract(amount);
}
}
public char multiply(char factor) {
synchronized (lock_) {
lock_.notifyAll();
return super.multiply(factor);
}
}
public char divide(char factor) {
synchronized (lock_) {
lock_.notifyAll();
return super.divide(factor);
}
}
/**
* Wait until value equals c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenEqual(char c, Runnable action) throws InterruptedException {
synchronized(lock_) {
while (!(value_ == c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value not equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenNotEqual(char c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ != c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value less than or equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenLessEqual(char c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ <= c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value less than c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenLess(char c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ < c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value greater than or equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenGreaterEqual(char c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ >= c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value greater than c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenGreater(char c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ > c)) lock_.wait();
if (action != null) action.run();
}
}
}
concurrent-dfsg-1.3.4/LayeredSync.java 0000644 0001750 0001750 00000004257 10202157355 020141 0 ustar wbaer wbaer 0000000 0000000 /*
File: LayeredSync.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
1Aug1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class that can be used to compose Syncs.
* A LayeredSync object manages two other Sync objects,
* outer and inner. The acquire operation
* invokes outer.acquire() followed by inner.acquire(),
* but backing out of outer (via release) upon an exception in inner.
* The other methods work similarly.
*
* LayeredSyncs can be used to compose arbitrary chains
* by arranging that either of the managed Syncs be another
* LayeredSync.
*
* [ Introduction to this package. ]
**/
public class LayeredSync implements Sync {
protected final Sync outer_;
protected final Sync inner_;
/**
* Create a LayeredSync managing the given outer and inner Sync
* objects
**/
public LayeredSync(Sync outer, Sync inner) {
outer_ = outer;
inner_ = inner;
}
public void acquire() throws InterruptedException {
outer_.acquire();
try {
inner_.acquire();
}
catch (InterruptedException ex) {
outer_.release();
throw ex;
}
}
public boolean attempt(long msecs) throws InterruptedException {
long start = (msecs <= 0)? 0 : System.currentTimeMillis();
long waitTime = msecs;
if (outer_.attempt(waitTime)) {
try {
if (msecs > 0)
waitTime = msecs - (System.currentTimeMillis() - start);
if (inner_.attempt(waitTime))
return true;
else {
outer_.release();
return false;
}
}
catch (InterruptedException ex) {
outer_.release();
throw ex;
}
}
else
return false;
}
public void release() {
inner_.release();
outer_.release();
}
}
concurrent-dfsg-1.3.4/BrokenBarrierException.java 0000644 0001750 0001750 00000002033 10202157355 022313 0 ustar wbaer wbaer 0000000 0000000 /*
File: BrokenBarrierException.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
29Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* Thrown by Barrier upon interruption of participant threads
**/
public class BrokenBarrierException extends RuntimeException {
/**
* The index that barrier would have returned upon
* normal return;
**/
public final int index;
/**
* Constructs a BrokenBarrierException with given index
**/
public BrokenBarrierException(int idx) {
index = idx;
}
/**
* Constructs a BrokenBarrierException with the
* specified index and detail message.
*/
public BrokenBarrierException(int idx, String message) {
super(message);
index = idx;
}
}
concurrent-dfsg-1.3.4/FutureResult.java 0000644 0001750 0001750 00000013426 10202157355 020366 0 ustar wbaer wbaer 0000000 0000000 /*
File: FutureResult.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
30Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.lang.reflect.*;
/**
* A class maintaining a single reference variable serving as the result
* of an operation. The result cannot be accessed until it has been set.
*
* Sample Usage
* [ Introduction to this package. ]
* @see Executor
**/
public class FutureResult {
/** The result of the operation **/
protected Object value_ = null;
/** Status -- true after first set **/
protected boolean ready_ = false;
/** the exception encountered by operation producing result **/
protected InvocationTargetException exception_ = null;
/**
* Create an initially unset FutureResult
**/
public FutureResult() { }
/**
* Return a Runnable object that, when run, will set the result value.
* @param function - a Callable object whose result will be
* held by this FutureResult.
* @return A Runnable object that, when run, will call the
* function and (eventually) set the result.
**/
public Runnable setter(final Callable function) {
return new Runnable() {
public void run() {
try {
set(function.call());
}
catch(Throwable ex) {
setException(ex);
}
}
};
}
/** internal utility: either get the value or throw the exception **/
protected Object doGet() throws InvocationTargetException {
if (exception_ != null)
throw exception_;
else
return value_;
}
/**
* Access the reference, waiting if necessary until it is ready.
* @return current value
* @exception InterruptedException if current thread has been interrupted
* @exception InvocationTargetException if the operation
* producing the value encountered an exception.
**/
public synchronized Object get()
throws InterruptedException, InvocationTargetException {
while (!ready_) wait();
return doGet();
}
/**
* Wait at most msecs to access the reference.
* @return current value
* @exception TimeoutException if not ready after msecs
* @exception InterruptedException if current thread has been interrupted
* @exception InvocationTargetException if the operation
* producing the value encountered an exception.
**/
public synchronized Object timedGet(long msecs)
throws TimeoutException, InterruptedException, InvocationTargetException {
long startTime = (msecs <= 0)? 0 : System.currentTimeMillis();
long waitTime = msecs;
if (ready_) return doGet();
else if (waitTime <= 0) throw new TimeoutException(msecs);
else {
for (;;) {
wait(waitTime);
if (ready_) return doGet();
else {
waitTime = msecs - (System.currentTimeMillis() - startTime);
if (waitTime <= 0)
throw new TimeoutException(msecs);
}
}
}
}
/**
* Set the reference, and signal that it is ready. It is not
* considered an error to set the value more than once,
* but it is not something you would normally want to do.
* @param newValue The value that will be returned by a subsequent get();
**/
public synchronized void set(Object newValue) {
value_ = newValue;
ready_ = true;
notifyAll();
}
/**
* Set the exception field, also setting ready status.
* @param ex The exception. It will be reported out wrapped
* within an InvocationTargetException
**/
public synchronized void setException(Throwable ex) {
exception_ = new InvocationTargetException(ex);
ready_ = true;
notifyAll();
}
/**
* Get the exception, or null if there isn't one (yet).
* This does not wait until the future is ready, so should
* ordinarily only be called if you know it is.
* @return the exception encountered by the operation
* setting the future, wrapped in an InvocationTargetException
**/
public synchronized InvocationTargetException getException() {
return exception_;
}
/**
* Return whether the reference or exception have been set.
* @return true if has been set. else false
**/
public synchronized boolean isReady() {
return ready_;
}
/**
* Access the reference, even if not ready
* @return current value
**/
public synchronized Object peek() {
return value_;
}
/**
* Clear the value and exception and set to not-ready,
* allowing this FutureResult to be reused. This is not
* particularly recommended and must be done only
* when you know that no other object is depending on the
* properties of this FutureResult.
**/
public synchronized void clear() {
value_ = null;
exception_ = null;
ready_ = false;
}
}
concurrent-dfsg-1.3.4/Latch.java 0000644 0001750 0001750 00000005523 10202157355 016747 0 ustar wbaer wbaer 0000000 0000000 /*
File: Latch.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A latch is a boolean condition that is set at most once, ever.
* Once a single release is issued, all acquires will pass.
*
* Sample usage. Here are a set of classes that use
* a latch as a start signal for a group of worker threads that
* are created and started beforehand, and then later enabled.
*
**/
public class Latch implements Sync {
protected boolean latched_ = false;
/*
This could use double-check, but doesn't.
If the latch is being used as an indicator of
the presence or state of an object, the user would
not necessarily get the memory barrier that comes with synch
that would be needed to correctly use that object. This
would lead to errors that users would be very hard to track down. So, to
be conservative, we always use synch.
*/
public void acquire() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
synchronized(this) {
while (!latched_)
wait();
}
}
public boolean attempt(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
synchronized(this) {
if (latched_)
return true;
else if (msecs <= 0)
return false;
else {
long waitTime = msecs;
long start = System.currentTimeMillis();
for (;;) {
wait(waitTime);
if (latched_)
return true;
else {
waitTime = msecs - (System.currentTimeMillis() - start);
if (waitTime <= 0)
return false;
}
}
}
}
}
/** Enable all current and future acquires to pass **/
public synchronized void release() {
latched_ = true;
notifyAll();
}
}
concurrent-dfsg-1.3.4/BoundedBuffer.java 0000644 0001750 0001750 00000011473 10202157355 020427 0 ustar wbaer wbaer 0000000 0000000 /*
File: BoundedBuffer.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
17Jul1998 dl Simplified by eliminating wait counts
25aug1998 dl added peek
5May1999 dl replace % with conditional (slightly faster)
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* Efficient array-based bounded buffer class.
* Adapted from CPJ, chapter 8, which describes design.
* [ Introduction to this package. ]
**/
public class BoundedBuffer implements BoundedChannel {
protected final Object[] array_; // the elements
protected int takePtr_ = 0; // circular indices
protected int putPtr_ = 0;
protected int usedSlots_ = 0; // length
protected int emptySlots_; // capacity - length
/**
* Helper monitor to handle puts.
**/
protected final Object putMonitor_ = new Object();
/**
* Create a BoundedBuffer with the given capacity.
* @exception IllegalArgumentException if capacity less or equal to zero
**/
public BoundedBuffer(int capacity) throws IllegalArgumentException {
if (capacity <= 0) throw new IllegalArgumentException();
array_ = new Object[capacity];
emptySlots_ = capacity;
}
/**
* Create a buffer with the current default capacity
**/
public BoundedBuffer() {
this(DefaultChannelCapacity.get());
}
/**
* Return the number of elements in the buffer.
* This is only a snapshot value, that may change
* immediately after returning.
**/
public synchronized int size() { return usedSlots_; }
public int capacity() { return array_.length; }
protected void incEmptySlots() {
synchronized(putMonitor_) {
++emptySlots_;
putMonitor_.notify();
}
}
protected synchronized void incUsedSlots() {
++usedSlots_;
notify();
}
protected final void insert(Object x) { // mechanics of put
--emptySlots_;
array_[putPtr_] = x;
if (++putPtr_ >= array_.length) putPtr_ = 0;
}
protected final Object extract() { // mechanics of take
--usedSlots_;
Object old = array_[takePtr_];
array_[takePtr_] = null;
if (++takePtr_ >= array_.length) takePtr_ = 0;
return old;
}
public Object peek() {
synchronized(this) {
if (usedSlots_ > 0)
return array_[takePtr_];
else
return null;
}
}
public void put(Object x) throws InterruptedException {
if (x == null) throw new IllegalArgumentException();
if (Thread.interrupted()) throw new InterruptedException();
synchronized(putMonitor_) {
while (emptySlots_ <= 0) {
try { putMonitor_.wait(); }
catch (InterruptedException ex) {
putMonitor_.notify();
throw ex;
}
}
insert(x);
}
incUsedSlots();
}
public boolean offer(Object x, long msecs) throws InterruptedException {
if (x == null) throw new IllegalArgumentException();
if (Thread.interrupted()) throw new InterruptedException();
synchronized(putMonitor_) {
long start = (msecs <= 0)? 0 : System.currentTimeMillis();
long waitTime = msecs;
while (emptySlots_ <= 0) {
if (waitTime <= 0) return false;
try { putMonitor_.wait(waitTime); }
catch (InterruptedException ex) {
putMonitor_.notify();
throw ex;
}
waitTime = msecs - (System.currentTimeMillis() - start);
}
insert(x);
}
incUsedSlots();
return true;
}
public Object take() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
Object old = null;
synchronized(this) {
while (usedSlots_ <= 0) {
try { wait(); }
catch (InterruptedException ex) {
notify();
throw ex;
}
}
old = extract();
}
incEmptySlots();
return old;
}
public Object poll(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
Object old = null;
synchronized(this) {
long start = (msecs <= 0)? 0 : System.currentTimeMillis();
long waitTime = msecs;
while (usedSlots_ <= 0) {
if (waitTime <= 0) return null;
try { wait(waitTime); }
catch (InterruptedException ex) {
notify();
throw ex;
}
waitTime = msecs - (System.currentTimeMillis() - start);
}
old = extract();
}
incEmptySlots();
return old;
}
}
concurrent-dfsg-1.3.4/WaitableFloat.java 0000644 0001750 0001750 00000010022 10202157355 020420 0 ustar wbaer wbaer 0000000 0000000 /*
File: WaitableFloat.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
23Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading waiting and signalling operations
* on single float variables.
*
* [ Introduction to this package. ]
**/
public class WaitableFloat extends SynchronizedFloat {
/**
* Make a new WaitableFloat with the given initial value,
* and using its own internal lock.
**/
public WaitableFloat(float initialValue) {
super(initialValue);
}
/**
* Make a new WaitableFloat with the given initial value,
* and using the supplied lock.
**/
public WaitableFloat(float initialValue, Object lock) {
super(initialValue, lock);
}
public float set(float newValue) {
synchronized (lock_) {
lock_.notifyAll();
return super.set(newValue);
}
}
public boolean commit(float assumedValue, float newValue) {
synchronized (lock_) {
boolean success = super.commit(assumedValue, newValue);
if (success) lock_.notifyAll();
return success;
}
}
public float add(float amount) {
synchronized (lock_) {
lock_.notifyAll();
return super.add(amount);
}
}
public float subtract(float amount) {
synchronized (lock_) {
lock_.notifyAll();
return super.subtract(amount);
}
}
public float multiply(float factor) {
synchronized (lock_) {
lock_.notifyAll();
return super.multiply(factor);
}
}
public float divide(float factor) {
synchronized (lock_) {
lock_.notifyAll();
return super.divide(factor);
}
}
/**
* Wait until value equals c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenEqual(float c, Runnable action) throws InterruptedException {
synchronized(lock_) {
while (!(value_ == c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value not equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenNotEqual(float c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ != c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value less than or equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenLessEqual(float c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ <= c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value less than c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenLess(float c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ < c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value greater than or equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenGreaterEqual(float c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ >= c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value greater than c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenGreater(float c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ > c)) lock_.wait();
if (action != null) action.run();
}
}
}
concurrent-dfsg-1.3.4/SyncCollection.java 0000644 0001750 0001750 00000032764 10202157355 020653 0 ustar wbaer wbaer 0000000 0000000 /*
File: SyncCollection.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
1Aug1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.util.*;
/**
* SyncCollections wrap Sync-based control around java.util.Collections.
* They are similar in operation to those provided
* by java.util.Collection.synchronizedCollection, but have
* several extended capabilities.
*
* The Collection interface is conceptually broken into two
* parts for purposes of synchronization control. The purely inspective
* reader operations are:
*
* SyncCollections can be used with either Syncs or ReadWriteLocks.
* When used with
* single Syncs, the same lock is used as both the reader and writer lock.
* The SyncCollection class cannot itself guarantee that using
* a pair of read/write locks will always correctly protect objects, since
* Collection implementations are not precluded from internally
* performing hidden unprotected state changes within conceptually read-only
* operations. However, they do work with current java.util implementations.
* (Hopefully, implementations that do not provide this natural
* guarantee will be clearly documentented as such.)
*
* This class provides a straight implementation of Collections interface.
* In order to conform to this interface, sync failures
* due to interruption do NOT result in InterruptedExceptions.
* Instead, upon detection of interruption,
*
* The iterator() method returns a SyncCollectionIterator with
* properties and methods that are analogous to those of SyncCollection
* itself: hasNext and next are read-only, and remove is mutative.
* These methods allow fine-grained controlled access, but do NOT
* preclude concurrent modifications from being interleaved with traversals,
* which may lead to ConcurrentModificationExceptions.
* However, the class also supports method
* (It would normally be better practice here to not make the
* collection accessible until initialization is complete.)
*
* This class does not specifically support use of
* timed synchronization through the attempt method. However,
* you can obtain this effect via
* the TimeoutSync class. For example:
*
* The same can be done with read-write locks:
*
* In addition to synchronization control, SyncCollections
* may be useful in any context requiring before/after methods
* surrounding collections. For example, you can use ObservableSync
* to arrange notifications on method calls to collections, as in:
* [ Introduction to this package. ]
* @see LayeredSync
* @see TimeoutSync
**/
public class SyncCollection implements Collection {
protected final Collection c_; // Backing Collection
protected final Sync rd_; // sync for read-only methods
protected final Sync wr_; // sync for mutative methods
protected final SynchronizedLong syncFailures_ = new SynchronizedLong(0);
/**
* Create a new SyncCollection protecting the given collection,
* and using the given sync to control both reader and writer methods.
* Common, reasonable choices for the sync argument include
* Mutex, ReentrantLock, and Semaphores initialized to 1.
*
* Sample Usage
*
* Sample Usage
*
* NullSyncs can be useful in optimizing classes when
* it is found that locking is not strictly necesssary.
*
* [ Introduction to this package. ]
**/
public class NullSync implements Sync {
public synchronized void acquire() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
}
public synchronized boolean attempt(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
return true;
}
public synchronized void release() {}
}
concurrent-dfsg-1.3.4/WaitableByte.java 0000644 0001750 0001750 00000012230 10202157355 020261 0 ustar wbaer wbaer 0000000 0000000 /*
File: WaitableByte.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
23Jun1998 dl Create public version
13may2004 dl Add notifying bit ops
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading waiting and signalling operations
* on single byte variables.
*
* [ Introduction to this package. ]
**/
public class WaitableByte extends SynchronizedByte {
/**
* Make a new WaitableByte with the given initial value,
* and using its own internal lock.
**/
public WaitableByte(byte initialValue) {
super(initialValue);
}
/**
* Make a new WaitableByte with the given initial value,
* and using the supplied lock.
**/
public WaitableByte(byte initialValue, Object lock) {
super(initialValue, lock);
}
public byte set(byte newValue) {
synchronized (lock_) {
lock_.notifyAll();
return super.set(newValue);
}
}
public boolean commit(byte assumedValue, byte newValue) {
synchronized (lock_) {
boolean success = super.commit(assumedValue, newValue);
if (success) lock_.notifyAll();
return success;
}
}
public byte increment() {
synchronized (lock_) {
lock_.notifyAll();
return super.increment();
}
}
public byte decrement() {
synchronized (lock_) {
lock_.notifyAll();
return super.decrement();
}
}
public byte add(byte amount) {
synchronized (lock_) {
lock_.notifyAll();
return super.add(amount);
}
}
public byte subtract(byte amount) {
synchronized (lock_) {
lock_.notifyAll();
return super.subtract(amount);
}
}
public byte multiply(byte factor) {
synchronized (lock_) {
lock_.notifyAll();
return super.multiply(factor);
}
}
public byte divide(byte factor) {
synchronized (lock_) {
lock_.notifyAll();
return super.divide(factor);
}
}
/**
* Set the value to its complement
* @return the new value
**/
public byte complement() {
synchronized (lock_) {
value_ = (byte)~value_;
lock_.notifyAll();
return value_;
}
}
/**
* Set value to value & b.
* @return the new value
**/
public byte and(byte b) {
synchronized (lock_) {
value_ = (byte)(value_ & b);
lock_.notifyAll();
return value_;
}
}
/**
* Set value to value | b.
* @return the new value
**/
public byte or(byte b) {
synchronized (lock_) {
value_ = (byte)(value_ | b);
lock_.notifyAll();
return value_;
}
}
/**
* Set value to value ^ b.
* @return the new value
**/
public byte xor(byte b) {
synchronized (lock_) {
value_ = (byte)(value_ ^ b);
lock_.notifyAll();
return value_;
}
}
/**
* Wait until value equals c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenEqual(byte c, Runnable action) throws InterruptedException {
synchronized(lock_) {
while (!(value_ == c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value not equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenNotEqual(byte c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ != c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value less than or equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenLessEqual(byte c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ <= c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value less than c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenLess(byte c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ < c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value greater than or equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenGreaterEqual(byte c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ >= c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value greater than c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenGreater(byte c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ > c)) lock_.wait();
if (action != null) action.run();
}
}
}
concurrent-dfsg-1.3.4/LinkedQueue.java 0000644 0001750 0001750 00000011550 10202157355 020124 0 ustar wbaer wbaer 0000000 0000000 /*
File: LinkedQueue.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
25aug1998 dl added peek
10dec1998 dl added isEmpty
10oct1999 dl lock on node object to ensure visibility
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A linked list based channel implementation.
* The algorithm avoids contention between puts
* and takes when the queue is not empty.
* Normally a put and a take can proceed simultaneously.
* (Although it does not allow multiple concurrent puts or takes.)
* This class tends to perform more efficently than
* other Channel implementations in producer/consumer
* applications.
* [ Introduction to this package. ]
**/
public class LinkedQueue implements Channel {
/**
* Dummy header node of list. The first actual node, if it exists, is always
* at head_.next. After each take, the old first node becomes the head.
**/
protected LinkedNode head_;
/**
* Helper monitor for managing access to last node.
**/
protected final Object putLock_ = new Object();
/**
* The last node of list. Put() appends to list, so modifies last_
**/
protected LinkedNode last_;
/**
* The number of threads waiting for a take.
* Notifications are provided in put only if greater than zero.
* The bookkeeping is worth it here since in reasonably balanced
* usages, the notifications will hardly ever be necessary, so
* the call overhead to notify can be eliminated.
**/
protected int waitingForTake_ = 0;
public LinkedQueue() {
head_ = new LinkedNode(null);
last_ = head_;
}
/** Main mechanics for put/offer **/
protected void insert(Object x) {
synchronized(putLock_) {
LinkedNode p = new LinkedNode(x);
synchronized(last_) {
last_.next = p;
last_ = p;
}
if (waitingForTake_ > 0)
putLock_.notify();
}
}
/** Main mechanics for take/poll **/
protected synchronized Object extract() {
synchronized(head_) {
Object x = null;
LinkedNode first = head_.next;
if (first != null) {
x = first.value;
first.value = null;
head_ = first;
}
return x;
}
}
public void put(Object x) throws InterruptedException {
if (x == null) throw new IllegalArgumentException();
if (Thread.interrupted()) throw new InterruptedException();
insert(x);
}
public boolean offer(Object x, long msecs) throws InterruptedException {
if (x == null) throw new IllegalArgumentException();
if (Thread.interrupted()) throw new InterruptedException();
insert(x);
return true;
}
public Object take() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
// try to extract. If fail, then enter wait-based retry loop
Object x = extract();
if (x != null)
return x;
else {
synchronized(putLock_) {
try {
++waitingForTake_;
for (;;) {
x = extract();
if (x != null) {
--waitingForTake_;
return x;
}
else {
putLock_.wait();
}
}
}
catch(InterruptedException ex) {
--waitingForTake_;
putLock_.notify();
throw ex;
}
}
}
}
public Object peek() {
synchronized(head_) {
LinkedNode first = head_.next;
if (first != null)
return first.value;
else
return null;
}
}
public boolean isEmpty() {
synchronized(head_) {
return head_.next == null;
}
}
public Object poll(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
Object x = extract();
if (x != null)
return x;
else {
synchronized(putLock_) {
try {
long waitTime = msecs;
long start = (msecs <= 0)? 0 : System.currentTimeMillis();
++waitingForTake_;
for (;;) {
x = extract();
if (x != null || waitTime <= 0) {
--waitingForTake_;
return x;
}
else {
putLock_.wait(waitTime);
waitTime = msecs - (System.currentTimeMillis() - start);
}
}
}
catch(InterruptedException ex) {
--waitingForTake_;
putLock_.notify();
throw ex;
}
}
}
}
}
concurrent-dfsg-1.3.4/ReentrantWriterPreferenceReadWriteLock.java 0000644 0001750 0001750 00000011221 10202157355 025462 0 ustar wbaer wbaer 0000000 0000000 /*
File: ReentrantWriterPreferenceReadWriteLock.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
26aug1998 dl Create public version
7sep2000 dl Readers are now also reentrant
19jan2001 dl Allow read->write upgrades if the only reader
10dec2002 dl Throw IllegalStateException on extra release
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.util.*;
/**
* A writer-preference ReadWriteLock that allows both readers and
* writers to reacquire
* read or write locks in the style of a ReentrantLock.
* Readers are not allowed until all write locks held by
* the writing thread have been released.
* Among other applications, reentrancy can be useful when
* write locks are held during calls or callbacks to methods that perform
* reads under read locks.
*
* Sample usage. Here is a code sketch showing how to exploit
* reentrancy to perform lock downgrading after updating a cache:
* [ Introduction to this package. ]
* @see ReentrantLock
**/
public class ReentrantWriterPreferenceReadWriteLock extends WriterPreferenceReadWriteLock {
/** Number of acquires on write lock by activeWriter_ thread **/
protected long writeHolds_ = 0;
/** Number of acquires on read lock by any reader thread **/
protected HashMap readers_ = new HashMap();
/** cache/reuse the special Integer value one to speed up readlocks **/
protected static final Integer IONE = new Integer(1);
protected boolean allowReader() {
return (activeWriter_ == null && waitingWriters_ == 0) ||
activeWriter_ == Thread.currentThread();
}
protected synchronized boolean startRead() {
Thread t = Thread.currentThread();
Object c = readers_.get(t);
if (c != null) { // already held -- just increment hold count
readers_.put(t, new Integer(((Integer)(c)).intValue()+1));
++activeReaders_;
return true;
}
else if (allowReader()) {
readers_.put(t, IONE);
++activeReaders_;
return true;
}
else
return false;
}
protected synchronized boolean startWrite() {
if (activeWriter_ == Thread.currentThread()) { // already held; re-acquire
++writeHolds_;
return true;
}
else if (writeHolds_ == 0) {
if (activeReaders_ == 0 ||
(readers_.size() == 1 &&
readers_.get(Thread.currentThread()) != null)) {
activeWriter_ = Thread.currentThread();
writeHolds_ = 1;
return true;
}
else
return false;
}
else
return false;
}
protected synchronized Signaller endRead() {
Thread t = Thread.currentThread();
Object c = readers_.get(t);
if (c == null)
throw new IllegalStateException();
--activeReaders_;
if (c != IONE) { // more than one hold; decrement count
int h = ((Integer)(c)).intValue()-1;
Integer ih = (h == 1)? IONE : new Integer(h);
readers_.put(t, ih);
return null;
}
else {
readers_.remove(t);
if (writeHolds_ > 0) // a write lock is still held by current thread
return null;
else if (activeReaders_ == 0 && waitingWriters_ > 0)
return writerLock_;
else
return null;
}
}
protected synchronized Signaller endWrite() {
--writeHolds_;
if (writeHolds_ > 0) // still being held
return null;
else {
activeWriter_ = null;
if (waitingReaders_ > 0 && allowReader())
return readerLock_;
else if (waitingWriters_ > 0)
return writerLock_;
else
return null;
}
}
}
concurrent-dfsg-1.3.4/WriterPreferenceReadWriteLock.java 0000644 0001750 0001750 00000021773 10202157355 023614 0 ustar wbaer wbaer 0000000 0000000 /*
File: WriterPreferenceReadWriteLock.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
5Aug1998 dl replaced int counters with longs
25aug1998 dl record writer thread
3May1999 dl add notifications on interrupt/timeout
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A ReadWriteLock that prefers waiting writers over
* waiting readers when there is contention. This class
* is adapted from the versions described in CPJ, improving
* on the ones there a bit by segregating reader and writer
* wait queues, which is typically more efficient.
*
* The locks are NOT reentrant. In particular,
* even though it may appear to usually work OK,
* a thread holding a read lock should not attempt to
* re-acquire it. Doing so risks lockouts when there are
* also waiting writers.
* [ Introduction to this package. ]
**/
public class WriterPreferenceReadWriteLock implements ReadWriteLock {
protected long activeReaders_ = 0;
protected Thread activeWriter_ = null;
protected long waitingReaders_ = 0;
protected long waitingWriters_ = 0;
protected final ReaderLock readerLock_ = new ReaderLock();
protected final WriterLock writerLock_ = new WriterLock();
public Sync writeLock() { return writerLock_; }
public Sync readLock() { return readerLock_; }
/*
A bunch of small synchronized methods are needed
to allow communication from the Lock objects
back to this object, that serves as controller
*/
protected synchronized void cancelledWaitingReader() { --waitingReaders_; }
protected synchronized void cancelledWaitingWriter() { --waitingWriters_; }
/** Override this method to change to reader preference **/
protected boolean allowReader() {
return activeWriter_ == null && waitingWriters_ == 0;
}
protected synchronized boolean startRead() {
boolean allowRead = allowReader();
if (allowRead) ++activeReaders_;
return allowRead;
}
protected synchronized boolean startWrite() {
// The allowWrite expression cannot be modified without
// also changing startWrite, so is hard-wired
boolean allowWrite = (activeWriter_ == null && activeReaders_ == 0);
if (allowWrite) activeWriter_ = Thread.currentThread();
return allowWrite;
}
/*
Each of these variants is needed to maintain atomicity
of wait counts during wait loops. They could be
made faster by manually inlining each other. We hope that
compilers do this for us though.
*/
protected synchronized boolean startReadFromNewReader() {
boolean pass = startRead();
if (!pass) ++waitingReaders_;
return pass;
}
protected synchronized boolean startWriteFromNewWriter() {
boolean pass = startWrite();
if (!pass) ++waitingWriters_;
return pass;
}
protected synchronized boolean startReadFromWaitingReader() {
boolean pass = startRead();
if (pass) --waitingReaders_;
return pass;
}
protected synchronized boolean startWriteFromWaitingWriter() {
boolean pass = startWrite();
if (pass) --waitingWriters_;
return pass;
}
/**
* Called upon termination of a read.
* Returns the object to signal to wake up a waiter, or null if no such
**/
protected synchronized Signaller endRead() {
if (--activeReaders_ == 0 && waitingWriters_ > 0)
return writerLock_;
else
return null;
}
/**
* Called upon termination of a write.
* Returns the object to signal to wake up a waiter, or null if no such
**/
protected synchronized Signaller endWrite() {
activeWriter_ = null;
if (waitingReaders_ > 0 && allowReader())
return readerLock_;
else if (waitingWriters_ > 0)
return writerLock_;
else
return null;
}
/**
* Reader and Writer requests are maintained in two different
* wait sets, by two different objects. These objects do not
* know whether the wait sets need notification since they
* don't know preference rules. So, each supports a
* method that can be selected by main controlling object
* to perform the notifications. This base class simplifies mechanics.
**/
protected abstract class Signaller { // base for ReaderLock and WriterLock
abstract void signalWaiters();
}
protected class ReaderLock extends Signaller implements Sync {
public void acquire() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
InterruptedException ie = null;
synchronized(this) {
if (!startReadFromNewReader()) {
for (;;) {
try {
ReaderLock.this.wait();
if (startReadFromWaitingReader())
return;
}
catch(InterruptedException ex){
cancelledWaitingReader();
ie = ex;
break;
}
}
}
}
if (ie != null) {
// fall through outside synch on interrupt.
// This notification is not really needed here,
// but may be in plausible subclasses
writerLock_.signalWaiters();
throw ie;
}
}
public void release() {
Signaller s = endRead();
if (s != null) s.signalWaiters();
}
synchronized void signalWaiters() { ReaderLock.this.notifyAll(); }
public boolean attempt(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
InterruptedException ie = null;
synchronized(this) {
if (msecs <= 0)
return startRead();
else if (startReadFromNewReader())
return true;
else {
long waitTime = msecs;
long start = System.currentTimeMillis();
for (;;) {
try { ReaderLock.this.wait(waitTime); }
catch(InterruptedException ex){
cancelledWaitingReader();
ie = ex;
break;
}
if (startReadFromWaitingReader())
return true;
else {
waitTime = msecs - (System.currentTimeMillis() - start);
if (waitTime <= 0) {
cancelledWaitingReader();
break;
}
}
}
}
}
// safeguard on interrupt or timeout:
writerLock_.signalWaiters();
if (ie != null) throw ie;
else return false; // timed out
}
}
protected class WriterLock extends Signaller implements Sync {
public void acquire() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
InterruptedException ie = null;
synchronized(this) {
if (!startWriteFromNewWriter()) {
for (;;) {
try {
WriterLock.this.wait();
if (startWriteFromWaitingWriter())
return;
}
catch(InterruptedException ex){
cancelledWaitingWriter();
WriterLock.this.notify();
ie = ex;
break;
}
}
}
}
if (ie != null) {
// Fall through outside synch on interrupt.
// On exception, we may need to signal readers.
// It is not worth checking here whether it is strictly necessary.
readerLock_.signalWaiters();
throw ie;
}
}
public void release(){
Signaller s = endWrite();
if (s != null) s.signalWaiters();
}
synchronized void signalWaiters() { WriterLock.this.notify(); }
public boolean attempt(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
InterruptedException ie = null;
synchronized(this) {
if (msecs <= 0)
return startWrite();
else if (startWriteFromNewWriter())
return true;
else {
long waitTime = msecs;
long start = System.currentTimeMillis();
for (;;) {
try { WriterLock.this.wait(waitTime); }
catch(InterruptedException ex){
cancelledWaitingWriter();
WriterLock.this.notify();
ie = ex;
break;
}
if (startWriteFromWaitingWriter())
return true;
else {
waitTime = msecs - (System.currentTimeMillis() - start);
if (waitTime <= 0) {
cancelledWaitingWriter();
WriterLock.this.notify();
break;
}
}
}
}
}
readerLock_.signalWaiters();
if (ie != null) throw ie;
else return false; // timed out
}
}
}
concurrent-dfsg-1.3.4/WaitableBoolean.java 0000644 0001750 0001750 00000006302 10202157355 020740 0 ustar wbaer wbaer 0000000 0000000 /*
File: WaitableBoolean.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
19Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading synch for boolean instance variables.
*
* [ Introduction to this package. ]
**/
public class WaitableBoolean extends SynchronizedBoolean {
/** Make a new WaitableBoolean with the given initial value **/
public WaitableBoolean(boolean initialValue) { super(initialValue); }
/**
* Make a new WaitableBoolean with the given initial value,
* and using the supplied lock.
**/
public WaitableBoolean(boolean initialValue, Object lock) {
super(initialValue, lock);
}
public boolean set(boolean newValue) {
synchronized (lock_) {
lock_.notifyAll();
return super.set(newValue);
}
}
public boolean commit(boolean assumedValue, boolean newValue) {
synchronized (lock_) {
boolean success = super.commit(assumedValue, newValue);
if (success) lock_.notifyAll();
return success;
}
}
public boolean complement() {
synchronized (lock_) {
lock_.notifyAll();
return super.complement();
}
}
public boolean and(boolean b) {
synchronized (lock_) {
lock_.notifyAll();
return super.and(b);
}
}
public boolean or(boolean b) {
synchronized (lock_) {
lock_.notifyAll();
return super.or(b);
}
}
public boolean xor(boolean b) {
synchronized (lock_) {
lock_.notifyAll();
return super.xor(b);
}
}
/**
* Wait until value is false, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenFalse(Runnable action) throws InterruptedException {
synchronized (lock_) {
while (value_) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value is true, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenTrue(Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!value_) lock_.wait();
if (action != null) action.run();
}
}
/**
* Wait until value equals c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenEqual(boolean c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ == c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value not equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenNotEqual(boolean c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ != c)) lock_.wait();
if (action != null) action.run();
}
}
}
concurrent-dfsg-1.3.4/SynchronizedVariable.java 0000644 0001750 0001750 00000017407 10202157355 022045 0 ustar wbaer wbaer 0000000 0000000 /*
File: SynchronizedVariable.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
30Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* Base class for simple, small classes
* maintaining single values that are always accessed
* and updated under synchronization. Since defining them for only
* some types seemed too arbitrary, they exist for all basic types,
* although it is hard to imagine uses for some.
*
* These classes mainly exist so that you do not have to go to the
* trouble of writing your own miscellaneous classes and methods
* in situations including:
*
* While they cannot, by nature, share much code,
* all of these classes work in the same way.
*
* Construction
* Update methods
*
*
*
* Guarded methods
* Other methods
* All classes except SynchronizedRef and WaitableRef implement
*
*
*
*
* [ Introduction to this package. ]
**/
public class SynchronizedVariable implements Executor {
protected final Object lock_;
/** Create a SynchronizedVariable using the supplied lock **/
public SynchronizedVariable(Object lock) { lock_ = lock; }
/** Create a SynchronizedVariable using itself as the lock **/
public SynchronizedVariable() { lock_ = this; }
/**
* Return the lock used for all synchronization for this object
**/
public Object getLock() { return lock_; }
/**
* If current thread is not interrupted, execute the given command
* within this object's lock
**/
public void execute(Runnable command) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
synchronized (lock_) {
command.run();
}
}
}
concurrent-dfsg-1.3.4/BoundedChannel.java 0000644 0001750 0001750 00000002135 10202157355 020561 0 ustar wbaer wbaer 0000000 0000000 /*
File: BoundedChannel.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A channel that is known to have a capacity, signifying
* that [ Introduction to this package. ]
**/
public interface BoundedChannel extends Channel {
/**
* Return the maximum number of elements that can be held.
* @return the capacity of this channel.
**/
public int capacity();
}
concurrent-dfsg-1.3.4/WaitableShort.java 0000644 0001750 0001750 00000012303 10202157355 020456 0 ustar wbaer wbaer 0000000 0000000 /*
File: WaitableShort.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
23Jun1998 dl Create public version
13may2004 dl Add notifying bit ops
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading waiting and signalling operations
* on single short variables.
*
* [ Introduction to this package. ]
**/
public class WaitableShort extends SynchronizedShort {
/**
* Make a new WaitableShort with the given initial value,
* and using its own internal lock.
**/
public WaitableShort(short initialValue) {
super(initialValue);
}
/**
* Make a new WaitableShort with the given initial value,
* and using the supplied lock.
**/
public WaitableShort(short initialValue, Object lock) {
super(initialValue, lock);
}
public short set(short newValue) {
synchronized (lock_) {
lock_.notifyAll();
return super.set(newValue);
}
}
public boolean commit(short assumedValue, short newValue) {
synchronized (lock_) {
boolean success = super.commit(assumedValue, newValue);
if (success) lock_.notifyAll();
return success;
}
}
public short increment() {
synchronized (lock_) {
lock_.notifyAll();
return super.increment();
}
}
public short decrement() {
synchronized (lock_) {
lock_.notifyAll();
return super.decrement();
}
}
public short add(short amount) {
synchronized (lock_) {
lock_.notifyAll();
return super.add(amount);
}
}
public short subtract(short amount) {
synchronized (lock_) {
lock_.notifyAll();
return super.subtract(amount);
}
}
public short multiply(short factor) {
synchronized (lock_) {
lock_.notifyAll();
return super.multiply(factor);
}
}
public short divide(short factor) {
synchronized (lock_) {
lock_.notifyAll();
return super.divide(factor);
}
}
/**
* Set the value to its complement
* @return the new value
**/
public short complement() {
synchronized (lock_) {
value_ = (short)(~value_);
lock_.notifyAll();
return value_;
}
}
/**
* Set value to value & b.
* @return the new value
**/
public short and(short b) {
synchronized (lock_) {
value_ = (short)(value_ & b);
lock_.notifyAll();
return value_;
}
}
/**
* Set value to value | b.
* @return the new value
**/
public short or(short b) {
synchronized (lock_) {
value_ = (short)(value_ | b);
lock_.notifyAll();
return value_;
}
}
/**
* Set value to value ^ b.
* @return the new value
**/
public short xor(short b) {
synchronized (lock_) {
value_ = (short)(value_ ^ b);
lock_.notifyAll();
return value_;
}
}
/**
* Wait until value equals c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenEqual(short c, Runnable action) throws InterruptedException {
synchronized(lock_) {
while (!(value_ == c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value not equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenNotEqual(short c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ != c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value less than or equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenLessEqual(short c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ <= c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value less than c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenLess(short c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ < c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value greater than or equal to c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenGreaterEqual(short c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ >= c)) lock_.wait();
if (action != null) action.run();
}
}
/**
* wait until value greater than c, then run action if nonnull.
* The action is run with the synchronization lock held.
**/
public void whenGreater(short c, Runnable action) throws InterruptedException {
synchronized (lock_) {
while (!(value_ > c)) lock_.wait();
if (action != null) action.run();
}
}
}
concurrent-dfsg-1.3.4/Puttable.java 0000644 0001750 0001750 00000005006 10202157355 017470 0 ustar wbaer wbaer 0000000 0000000 /*
File: Puttable.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* This interface exists to enable stricter type checking
* for channels. A method argument or instance variable
* in a producer object can be declared as only a Puttable
* rather than a Channel, in which case a Java compiler
* will disallow take operations.
*
* Full method descriptions appear in the Channel interface.
* [ Introduction to this package. ]
* @see Channel
* @see Takable
**/
public interface Puttable {
/**
* Place item in the channel, possibly waiting indefinitely until
* it can be accepted. Channels implementing the BoundedChannel
* subinterface are generally guaranteed to block on puts upon
* reaching capacity, but other implementations may or may not block.
* @param item the element to be inserted. Should be non-null.
* @exception InterruptedException if the current thread has
* been interrupted at a point at which interruption
* is detected, in which case the element is guaranteed not
* to be inserted. Otherwise, on normal return, the element is guaranteed
* to have been inserted.
**/
public void put(Object item) throws InterruptedException;
/**
* Place item in channel only if it can be accepted within
* msecs milliseconds. The time bound is interpreted in
* a coarse-grained, best-effort fashion.
* @param item the element to be inserted. Should be non-null.
* @param msecs the number of milliseconds to wait. If less than
* or equal to zero, the method does not perform any timed waits,
* but might still require
* access to a synchronization lock, which can impose unbounded
* delay if there is a lot of contention for the channel.
* @return true if accepted, else false
* @exception InterruptedException if the current thread has
* been interrupted at a point at which interruption
* is detected, in which case the element is guaranteed not
* to be inserted (i.e., is equivalent to a false return).
**/
public boolean offer(Object item, long msecs) throws InterruptedException;
}
concurrent-dfsg-1.3.4/QueuedSemaphore.java 0000644 0001750 0001750 00000011400 10202157355 020777 0 ustar wbaer wbaer 0000000 0000000 /*
File: QueuedSemaphore.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
5Aug1998 dl replaced int counters with longs
24Aug1999 dl release(n): screen arguments
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* Abstract base class for semaphores relying on queued wait nodes.
* [ Introduction to this package. ]
**/
public abstract class QueuedSemaphore extends Semaphore {
protected final WaitQueue wq_;
QueuedSemaphore(WaitQueue q, long initialPermits) {
super(initialPermits);
wq_ = q;
}
public void acquire() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
if (precheck()) return;
WaitQueue.WaitNode w = new WaitQueue.WaitNode();
w.doWait(this);
}
public boolean attempt(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
if (precheck()) return true;
if (msecs <= 0) return false;
WaitQueue.WaitNode w = new WaitQueue.WaitNode();
return w.doTimedWait(this, msecs);
}
protected synchronized boolean precheck() {
boolean pass = (permits_ > 0);
if (pass) --permits_;
return pass;
}
protected synchronized boolean recheck(WaitQueue.WaitNode w) {
boolean pass = (permits_ > 0);
if (pass) --permits_;
else wq_.insert(w);
return pass;
}
protected synchronized WaitQueue.WaitNode getSignallee() {
WaitQueue.WaitNode w = wq_.extract();
if (w == null) ++permits_; // if none, inc permits for new arrivals
return w;
}
public void release() {
for (;;) {
WaitQueue.WaitNode w = getSignallee();
if (w == null) return; // no one to signal
if (w.signal()) return; // notify if still waiting, else skip
}
}
/** Release N permits **/
public void release(long n) {
if (n < 0) throw new IllegalArgumentException("Negative argument");
for (long i = 0; i < n; ++i) release();
}
/**
* Base class for internal queue classes for semaphores, etc.
* Relies on subclasses to actually implement queue mechanics
**/
protected static abstract class WaitQueue {
protected abstract void insert(WaitNode w);// assumed not to block
protected abstract WaitNode extract(); // should return null if empty
protected static class WaitNode {
boolean waiting = true;
WaitNode next = null;
protected synchronized boolean signal() {
boolean signalled = waiting;
if (signalled) {
waiting = false;
notify();
}
return signalled;
}
protected synchronized boolean doTimedWait(QueuedSemaphore sem,
long msecs)
throws InterruptedException {
if (sem.recheck(this) || !waiting)
return true;
else if (msecs <= 0) {
waiting = false;
return false;
}
else {
long waitTime = msecs;
long start = System.currentTimeMillis();
try {
for (;;) {
wait(waitTime);
if (!waiting) // definitely signalled
return true;
else {
waitTime = msecs - (System.currentTimeMillis() - start);
if (waitTime <= 0) { // timed out
waiting = false;
return false;
}
}
}
}
catch(InterruptedException ex) {
if (waiting) { // no notification
waiting = false; // invalidate for the signaller
throw ex;
}
else { // thread was interrupted after it was notified
Thread.currentThread().interrupt();
return true;
}
}
}
}
protected synchronized void doWait(QueuedSemaphore sem)
throws InterruptedException {
if (!sem.recheck(this)) {
try {
while (waiting) wait();
}
catch(InterruptedException ex) {
if (waiting) { // no notification
waiting = false; // invalidate for the signaller
throw ex;
}
else { // thread was interrupted after it was notified
Thread.currentThread().interrupt();
return;
}
}
}
}
}
}
}
concurrent-dfsg-1.3.4/PooledExecutor.java 0000644 0001750 0001750 00000100461 10202157355 020652 0 ustar wbaer wbaer 0000000 0000000 /*
File: PooledExecutor.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
19Jun1998 dl Create public version
29aug1998 dl rely on ThreadFactoryUser,
remove ThreadGroup-based methods
adjusted locking policies
3mar1999 dl Worker threads sense decreases in pool size
31mar1999 dl Allow supplied channel in constructor;
add methods createThreads, drain
15may1999 dl Allow infinite keepalives
21oct1999 dl add minimumPoolSize methods
7sep2000 dl BlockedExecutionHandler now an interface,
new DiscardOldestWhenBlocked policy
12oct2000 dl add shutdownAfterProcessingCurrentlyQueuedTasks
13nov2000 dl null out task ref after run
08apr2001 dl declare inner class ctor protected
12nov2001 dl Better shutdown support
Blocked exec handlers can throw IE
Simplify locking scheme
25jan2001 dl {get,set}BlockedExecutionHandler now public
17may2002 dl null out task var in worker run to enable GC.
30aug2003 dl check for new tasks when timing out
18feb2004 dl replace dead thread if no others left
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.util.*;
/**
* A tunable, extensible thread pool class. The main supported public
* method is
* Thread pools can be useful for several, usually intertwined
* reasons:
*
*
*
* When given a choice, this pool always prefers adding a new thread
* rather than queueing if there are currently fewer than the
* current getMinimumPoolSize threads running, but otherwise always
* prefers queuing a request rather than adding a new thread. Thus,
* if you use an unbounded buffer, you will never have more than
* getMinimumPoolSize threads running. (Since the default
* minimumPoolSize is one, you will probably want to explicitly
* setMinimumPoolSize.)
*
* While queuing can be useful in smoothing out transient bursts of
* requests, especially in socket-based services, it is not very
* well behaved when commands continue to arrive on average faster
* than they can be processed. Using bounds for both the queue and
* the pool size, along with run-when-blocked policy is often a
* reasonable response to such possibilities.
*
* Queue sizes and maximum pool sizes can often be traded off for
* each other. Using large queues and small pools minimizes CPU
* usage, OS resources, and context-switching overhead, but can lead
* to artifically low throughput. Especially if tasks frequently
* block (for example if they are I/O bound), a JVM and underlying
* OS may be able to schedule time for more threads than you
* otherwise allow. Use of small queues or queueless handoffs
* generally requires larger pool sizes, which keeps CPUs busier but
* may encounter unacceptable scheduling overhead, which also
* decreases throughput.
*
*
*
*
*
*
*
*
*
* To establish worker threads permanently, use a negative
* argument to setKeepAliveTime.
*
*
*
*
*
* These cases can never occur if the maximum pool size is unbounded
* or the queue is unbounded. In these cases you instead face
* potential resource exhaustion.) The execute method does not
* throw any checked exceptions in any of these cases since any
* errors associated with them must normally be dealt with via
* handlers or callbacks. (Although in some cases, these might be
* associated with throwing unchecked exceptions.) You may wish to
* add special implementations even if you choose one of the listed
* policies. For example, the supplied Discard policy does not
* inform the caller of the drop. You could add your own version
* that does so. Since choice of policies is normally a system-wide
* decision, selecting a policy affects all calls to
*
*
*
*
*
*
*
*
* Also, if you are
* using some form of queuing, you may wish to call method drain()
* to remove (and return) unprocessed commands from the queue after
* shutting down the pool and its clients. If you need to be sure
* these commands are processed, you can then run() each of the
* commands in the list returned by drain().
*
*
*
* Usage examples.
*
*
* Probably the most common use of pools is in statics or singletons
* accessible from a number of classes in a package; for example:
*
*
* Usage notes.
*
*
* Pools do not mesh well with using thread-specific storage via
* java.lang.ThreadLocal. ThreadLocal relies on the identity of a
* thread executing a particular task. Pools use the same thread to
* perform different tasks.
*
* If you need a policy not handled by the parameters in this class
* consider writing a subclass.
*
* Version note: Previous versions of this class relied on
* ThreadGroups for aggregate control. This has been removed, and the
* method interruptAll added, to avoid differences in behavior across
* JVMs.
*
* [ Introduction to this package. ]
**/
public class PooledExecutor extends ThreadFactoryUser implements Executor {
/**
* The maximum pool size; used if not otherwise specified. Default
* value is essentially infinite (Integer.MAX_VALUE)
**/
public static final int DEFAULT_MAXIMUMPOOLSIZE = Integer.MAX_VALUE;
/**
* The minimum pool size; used if not otherwise specified. Default
* value is 1.
**/
public static final int DEFAULT_MINIMUMPOOLSIZE = 1;
/**
* The maximum time to keep worker threads alive waiting for new
* tasks; used if not otherwise specified. Default value is one
* minute (60000 milliseconds).
**/
public static final long DEFAULT_KEEPALIVETIME = 60 * 1000;
/** The maximum number of threads allowed in pool. **/
protected int maximumPoolSize_ = DEFAULT_MAXIMUMPOOLSIZE;
/** The minumum number of threads to maintain in pool. **/
protected int minimumPoolSize_ = DEFAULT_MINIMUMPOOLSIZE;
/** Current pool size. **/
protected int poolSize_ = 0;
/** The maximum time for an idle thread to wait for new task. **/
protected long keepAliveTime_ = DEFAULT_KEEPALIVETIME;
/**
* Shutdown flag - latches true when a shutdown method is called
* in order to disable queuing/handoffs of new tasks.
**/
protected boolean shutdown_ = false;
/**
* The channel used to hand off the command to a thread in the pool.
**/
protected final Channel handOff_;
/**
* The set of active threads, declared as a map from workers to
* their threads. This is needed by the interruptAll method. It
* may also be useful in subclasses that need to perform other
* thread management chores.
**/
protected final Map threads_;
/** The current handler for unserviceable requests. **/
protected BlockedExecutionHandler blockedExecutionHandler_;
/**
* Create a new pool with all default settings
**/
public PooledExecutor() {
this (new SynchronousChannel(), DEFAULT_MAXIMUMPOOLSIZE);
}
/**
* Create a new pool with all default settings except
* for maximum pool size.
**/
public PooledExecutor(int maxPoolSize) {
this(new SynchronousChannel(), maxPoolSize);
}
/**
* Create a new pool that uses the supplied Channel for queuing, and
* with all default parameter settings.
**/
public PooledExecutor(Channel channel) {
this(channel, DEFAULT_MAXIMUMPOOLSIZE);
}
/**
* Create a new pool that uses the supplied Channel for queuing, and
* with all default parameter settings except for maximum pool size.
**/
public PooledExecutor(Channel channel, int maxPoolSize) {
maximumPoolSize_ = maxPoolSize;
handOff_ = channel;
runWhenBlocked();
threads_ = new HashMap();
}
/**
* Return the maximum number of threads to simultaneously execute
* New unqueued requests will be handled according to the current
* blocking policy once this limit is exceeded.
**/
public synchronized int getMaximumPoolSize() {
return maximumPoolSize_;
}
/**
* Set the maximum number of threads to use. Decreasing the pool
* size will not immediately kill existing threads, but they may
* later die when idle.
* @exception IllegalArgumentException if less or equal to zero.
* (It is
* not considered an error to set the maximum to be less than than
* the minimum. However, in this case there are no guarantees
* about behavior.)
**/
public synchronized void setMaximumPoolSize(int newMaximum) {
if (newMaximum <= 0) throw new IllegalArgumentException();
maximumPoolSize_ = newMaximum;
}
/**
* Return the minimum number of threads to simultaneously execute.
* (Default value is 1). If fewer than the mininum number are
* running upon reception of a new request, a new thread is started
* to handle this request.
**/
public synchronized int getMinimumPoolSize() {
return minimumPoolSize_;
}
/**
* Set the minimum number of threads to use.
* @exception IllegalArgumentException if less than zero. (It is not
* considered an error to set the minimum to be greater than the
* maximum. However, in this case there are no guarantees about
* behavior.)
**/
public synchronized void setMinimumPoolSize(int newMinimum) {
if (newMinimum < 0) throw new IllegalArgumentException();
minimumPoolSize_ = newMinimum;
}
/**
* Return the current number of active threads in the pool. This
* number is just a snaphot, and may change immediately upon
* returning
**/
public synchronized int getPoolSize() {
return poolSize_;
}
/**
* Return the number of milliseconds to keep threads alive waiting
* for new commands. A negative value means to wait forever. A zero
* value means not to wait at all.
**/
public synchronized long getKeepAliveTime() {
return keepAliveTime_;
}
/**
* Set the number of milliseconds to keep threads alive waiting for
* new commands. A negative value means to wait forever. A zero
* value means not to wait at all.
**/
public synchronized void setKeepAliveTime(long msecs) {
keepAliveTime_ = msecs;
}
/** Get the handler for blocked execution **/
public synchronized BlockedExecutionHandler getBlockedExecutionHandler() {
return blockedExecutionHandler_;
}
/** Set the handler for blocked execution **/
public synchronized void setBlockedExecutionHandler(BlockedExecutionHandler h) {
blockedExecutionHandler_ = h;
}
/**
* Create and start a thread to handle a new command. Call only
* when holding lock.
**/
protected void addThread(Runnable command) {
Worker worker = new Worker(command);
Thread thread = getThreadFactory().newThread(worker);
threads_.put(worker, thread);
++poolSize_;
thread.start();
}
/**
* Create and start up to numberOfThreads threads in the pool.
* Return the number created. This may be less than the number
* requested if creating more would exceed maximum pool size bound.
**/
public int createThreads(int numberOfThreads) {
int ncreated = 0;
for (int i = 0; i < numberOfThreads; ++i) {
synchronized(this) {
if (poolSize_ < maximumPoolSize_) {
addThread(null);
++ncreated;
}
else
break;
}
}
return ncreated;
}
/**
* Interrupt all threads in the pool, causing them all to
* terminate. Assuming that executed tasks do not disable (clear)
* interruptions, each thread will terminate after processing its
* current task. Threads will terminate sooner if the executed tasks
* themselves respond to interrupts.
**/
public synchronized void interruptAll() {
for (Iterator it = threads_.values().iterator(); it.hasNext(); ) {
Thread t = (Thread)(it.next());
t.interrupt();
}
}
/**
* Interrupt all threads and disable construction of new
* threads. Any tasks entered after this point will be discarded. A
* shut down pool cannot be restarted.
*/
public void shutdownNow() {
shutdownNow(new DiscardWhenBlocked());
}
/**
* Interrupt all threads and disable construction of new
* threads. Any tasks entered after this point will be handled by
* the given BlockedExecutionHandler. A shut down pool cannot be
* restarted.
*/
public synchronized void shutdownNow(BlockedExecutionHandler handler) {
setBlockedExecutionHandler(handler);
shutdown_ = true; // don't allow new tasks
minimumPoolSize_ = maximumPoolSize_ = 0; // don't make new threads
interruptAll(); // interrupt all existing threads
}
/**
* Terminate threads after processing all elements currently in
* queue. Any tasks entered after this point will be discarded. A
* shut down pool cannot be restarted.
**/
public void shutdownAfterProcessingCurrentlyQueuedTasks() {
shutdownAfterProcessingCurrentlyQueuedTasks(new DiscardWhenBlocked());
}
/**
* Terminate threads after processing all elements currently in
* queue. Any tasks entered after this point will be handled by the
* given BlockedExecutionHandler. A shut down pool cannot be
* restarted.
**/
public synchronized void shutdownAfterProcessingCurrentlyQueuedTasks(BlockedExecutionHandler handler) {
setBlockedExecutionHandler(handler);
shutdown_ = true;
if (poolSize_ == 0) // disable new thread construction when idle
minimumPoolSize_ = maximumPoolSize_ = 0;
}
/**
* Return true if a shutDown method has succeeded in terminating all
* threads.
*/
public synchronized boolean isTerminatedAfterShutdown() {
return shutdown_ && poolSize_ == 0;
}
/**
* Wait for a shutdown pool to fully terminate, or until the timeout
* has expired. This method may only be called after
* invoking shutdownNow or
* shutdownAfterProcessingCurrentlyQueuedTasks.
*
* @param maxWaitTime the maximum time in milliseconds to wait
* @return true if the pool has terminated within the max wait period
* @exception IllegalStateException if shutdown has not been requested
* @exception InterruptedException if the current thread has been interrupted in the course of waiting
*/
public synchronized boolean awaitTerminationAfterShutdown(long maxWaitTime) throws InterruptedException {
if (!shutdown_)
throw new IllegalStateException();
if (poolSize_ == 0)
return true;
long waitTime = maxWaitTime;
if (waitTime <= 0)
return false;
long start = System.currentTimeMillis();
for (;;) {
wait(waitTime);
if (poolSize_ == 0)
return true;
waitTime = maxWaitTime - (System.currentTimeMillis() - start);
if (waitTime <= 0)
return false;
}
}
/**
* Wait for a shutdown pool to fully terminate. This method may
* only be called after invoking shutdownNow or
* shutdownAfterProcessingCurrentlyQueuedTasks.
*
* @exception IllegalStateException if shutdown has not been requested
* @exception InterruptedException if the current thread has been interrupted in the course of waiting
*/
public synchronized void awaitTerminationAfterShutdown() throws InterruptedException {
if (!shutdown_)
throw new IllegalStateException();
while (poolSize_ > 0)
wait();
}
/**
* Remove all unprocessed tasks from pool queue, and return them in
* a java.util.List. Thsi method should be used only when there are
* not any active clients of the pool. Otherwise you face the
* possibility that the method will loop pulling out tasks as
* clients are putting them in. This method can be useful after
* shutting down a pool (via shutdownNow) to determine whether there
* are any pending tasks that were not processed. You can then, for
* example execute all unprocessed commands via code along the lines
* of:
*
* [ Introduction to this package. ]
**/
public interface Barrier {
/**
* Return the number of parties that must meet per barrier
* point. The number of parties is always at least 1.
**/
public int parties();
/**
* Returns true if the barrier has been compromised
* by threads leaving the barrier before a synchronization
* point (normally due to interruption or timeout).
* Barrier methods in implementation classes throw
* throw BrokenBarrierException upon detection of breakage.
* Implementations may also support some means
* to clear this status.
**/
public boolean broken();
}
concurrent-dfsg-1.3.4/SynchronizedDouble.java 0000644 0001750 0001750 00000010404 10202157355 021520 0 ustar wbaer wbaer 0000000 0000000 /*
File: SynchronizedDouble.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
19Jun1998 dl Create public version
15Apr2003 dl Removed redundant "synchronized" for multiply()
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading synch for double instance variables.
*
* [ Introduction to this package. ]
**/
public class SynchronizedDouble extends SynchronizedVariable implements Comparable, Cloneable {
protected double value_;
/**
* Make a new SynchronizedDouble with the given initial value,
* and using its own internal lock.
**/
public SynchronizedDouble(double initialValue) {
super();
value_ = initialValue;
}
/**
* Make a new SynchronizedDouble with the given initial value,
* and using the supplied lock.
**/
public SynchronizedDouble(double initialValue, Object lock) {
super(lock);
value_ = initialValue;
}
/**
* Return the current value
**/
public final double get() { synchronized(lock_) { return value_; } }
/**
* Set to newValue.
* @return the old value
**/
public double set(double newValue) {
synchronized (lock_) {
double old = value_;
value_ = newValue;
return old;
}
}
/**
* Set value to newValue only if it is currently assumedValue.
* @return true if successful
**/
public boolean commit(double assumedValue, double newValue) {
synchronized(lock_) {
boolean success = (assumedValue == value_);
if (success) value_ = newValue;
return success;
}
}
/**
* Atomically swap values with another SynchronizedDouble.
* Uses identityHashCode to avoid deadlock when
* two SynchronizedDoubles attempt to simultaneously swap with each other.
* (Note: Ordering via identyHashCode is not strictly guaranteed
* by the language specification to return unique, orderable
* values, but in practice JVMs rely on them being unique.)
* @return the new value
**/
public double swap(SynchronizedDouble other) {
if (other == this) return get();
SynchronizedDouble fst = this;
SynchronizedDouble snd = other;
if (System.identityHashCode(fst) > System.identityHashCode(snd)) {
fst = other;
snd = this;
}
synchronized(fst.lock_) {
synchronized(snd.lock_) {
fst.set(snd.set(fst.get()));
return get();
}
}
}
/**
* Add amount to value (i.e., set value += amount)
* @return the new value
**/
public double add(double amount) {
synchronized (lock_) {
return value_ += amount;
}
}
/**
* Subtract amount from value (i.e., set value -= amount)
* @return the new value
**/
public double subtract(double amount) {
synchronized (lock_) {
return value_ -= amount;
}
}
/**
* Multiply value by factor (i.e., set value *= factor)
* @return the new value
**/
public double multiply(double factor) {
synchronized (lock_) {
return value_ *= factor;
}
}
/**
* Divide value by factor (i.e., set value /= factor)
* @return the new value
**/
public double divide(double factor) {
synchronized (lock_) {
return value_ /= factor;
}
}
public int compareTo(double other) {
double val = get();
return (val < other)? -1 : (val == other)? 0 : 1;
}
public int compareTo(SynchronizedDouble other) {
return compareTo(other.get());
}
public int compareTo(Object other) {
return compareTo((SynchronizedDouble)other);
}
public boolean equals(Object other) {
if (other != null &&
other instanceof SynchronizedDouble)
return get() == ((SynchronizedDouble)other).get();
else
return false;
}
public int hashCode() { // same hash as Double
long bits = Double.doubleToLongBits(get());
return (int)(bits ^ (bits >> 32));
}
public String toString() { return String.valueOf(get()); }
}
concurrent-dfsg-1.3.4/ReaderPreferenceReadWriteLock.java 0000644 0001750 0001750 00000001776 10202157355 023543 0 ustar wbaer wbaer 0000000 0000000 /*
File: ReaderPreferenceReadWriteLock.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A ReadWriteLock that prefers waiting readers over
* waiting writers when there is contention. The range of applicability
* of this class is very limited. In the majority of situations,
* writer preference locks provide more reasonable semantics.
*
* [ Introduction to this package. ]
**/
public class ReaderPreferenceReadWriteLock extends WriterPreferenceReadWriteLock {
protected boolean allowReader() {
return activeWriter_ == null;
}
}
concurrent-dfsg-1.3.4/SyncSortedMap.java 0000644 0001750 0001750 00000006312 10202157355 020444 0 ustar wbaer wbaer 0000000 0000000 /*
File: SyncSortedMap.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
1Aug1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.util.*;
/**
* SyncSortedMaps wrap Sync-based control around java.util.SortedMaps.
* They support the following additional reader operations over
* SyncMap: comparator, subMap, headMap, tailMap, firstKey, lastKey.
* [ Introduction to this package. ]
* @see SyncCollection
**/
public class SyncSortedMap extends SyncMap implements SortedMap {
/**
* Create a new SyncSortedMap protecting the given map,
* and using the given sync to control both reader and writer methods.
* Common, reasonable choices for the sync argument include
* Mutex, ReentrantLock, and Semaphores initialized to 1.
**/
public SyncSortedMap(SortedMap map, Sync sync) {
this (map, sync, sync);
}
/**
* Create a new SyncSortedMap protecting the given map,
* and using the given ReadWriteLock to control reader and writer methods.
**/
public SyncSortedMap(SortedMap map, ReadWriteLock rwl) {
super (map, rwl.readLock(), rwl.writeLock());
}
/**
* Create a new SyncSortedMap protecting the given map,
* and using the given pair of locks to control reader and writer methods.
**/
public SyncSortedMap(SortedMap map, Sync readLock, Sync writeLock) {
super(map, readLock, writeLock);
}
protected SortedMap baseSortedMap() {
return (SortedMap)c_;
}
public Comparator comparator() {
boolean wasInterrupted = beforeRead();
try {
return baseSortedMap().comparator();
}
finally {
afterRead(wasInterrupted);
}
}
public Object firstKey() {
boolean wasInterrupted = beforeRead();
try {
return baseSortedMap().firstKey();
}
finally {
afterRead(wasInterrupted);
}
}
public Object lastKey() {
boolean wasInterrupted = beforeRead();
try {
return baseSortedMap().lastKey();
}
finally {
afterRead(wasInterrupted);
}
}
public SortedMap subMap(Object fromElement, Object toElement) {
boolean wasInterrupted = beforeRead();
try {
return new SyncSortedMap(baseSortedMap().subMap(fromElement, toElement),
rd_, wr_);
}
finally {
afterRead(wasInterrupted);
}
}
public SortedMap headMap(Object toElement) {
boolean wasInterrupted = beforeRead();
try {
return new SyncSortedMap(baseSortedMap().headMap(toElement),
rd_, wr_);
}
finally {
afterRead(wasInterrupted);
}
}
public SortedMap tailMap(Object fromElement) {
boolean wasInterrupted = beforeRead();
try {
return new SyncSortedMap(baseSortedMap().tailMap(fromElement),
rd_, wr_);
}
finally {
afterRead(wasInterrupted);
}
}
}
concurrent-dfsg-1.3.4/TimeoutException.java 0000644 0001750 0001750 00000002540 10202157355 021215 0 ustar wbaer wbaer 0000000 0000000 /*
File: TimeoutException.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
29Jun1998 dl Create public version
4Aug1998 dl Change to extend InterruptedException
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* Thrown by synchronization classes that report
* timeouts via exceptions. The exception is treated
* as a form (subclass) of InterruptedException. This both
* simplifies handling, and conceptually reflects the fact that
* timed-out operations are artificially interrupted by timers.
**/
public class TimeoutException extends InterruptedException {
/**
* The approximate time that the operation lasted before
* this timeout exception was thrown.
**/
public final long duration;
/**
* Constructs a TimeoutException with given duration value.
**/
public TimeoutException(long time) {
duration = time;
}
/**
* Constructs a TimeoutException with the
* specified duration value and detail message.
*/
public TimeoutException(long time, String message) {
super(message);
duration = time;
}
}
concurrent-dfsg-1.3.4/FJTask.java 0000644 0001750 0001750 00000044316 10202157355 017041 0 ustar wbaer wbaer 0000000 0000000 /*
File: Task.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
7Jan1999 dl first release
14jan1999 dl simplify start() semantics;
improve documentation
18Jan1999 dl Eliminate useless time-based waits.
7Mar1999 dl Add reset method,
add array-based composite operations
27Apr1999 dl Rename
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* Abstract base class for Fork/Join Tasks.
*
*
* FJTasks are lightweight, stripped-down analogs of Threads.
* Many FJTasks share the same pool of Java threads. This is
* supported by the FJTaskRunnerGroup and FJTaskRunner classes, that
* mainly contain
* methods called only internally by FJTasks.
* FJTasks support versions of the most common methods found in class Thread,
* including start(), yield() and join(). However, they
* don't support priorities, ThreadGroups or other bookkeeping
* or control methods of class Thread.
*
* FJTasks should normally be defined by subclassing and adding a run() method.
* Alternatively, static inner class
*
* There are three different ways to run a FJTask,
* with different scheduling semantics:
*
* The main economies of FJTasks stem from the fact that
* FJTasks do not support blocking operations of any kind.
* FJTasks should just run to completion without
* issuing waits or performing blocking IO.
* There are several styles for creating the run methods that
* execute as tasks, including
* event-style methods, and pure computational methods.
* Generally, the best kinds of FJTasks are those that in turn
* generate other FJTasks.
*
* There is nothing actually
* preventing you from blocking within a FJTask, and very short waits/blocks are
* completely well behaved. But FJTasks are not designed
* to support arbitrary synchronization
* since there is no way to suspend and resume individual tasks
* once they have begun executing. FJTasks should also be finite
* in duration -- they should not contain infinite loops.
* FJTasks that might need to perform a blocking
* action, or hold locks for extended periods, or
* loop forever can instead create normal
* java Thread objects that will do so. FJTasks are just not
* designed to support these things.
* FJTasks may however yield() control to allow their FJTaskRunner threads
* to run other tasks,
* and may wait for other dependent tasks via join(). These
* are the only coordination mechanisms supported by FJTasks.
*
* FJTasks, and the FJTaskRunners that execute them are not
* intrinsically robust with respect to exceptions.
* A FJTask that aborts via an exception does not automatically
* have its completion flag (isDone) set.
* As with ordinary Threads, an uncaught exception will normally cause
* its FJTaskRunner thread to die, which in turn may sometimes
* cause other computations being performed to hang or abort.
* You can of course
* do better by trapping exceptions inside the run methods of FJTasks.
*
* The overhead differences between FJTasks and Threads are substantial,
* especially when using fork() or coInvoke().
* FJTasks can be two or three orders of magnitude faster than Threads,
* at least when run on JVMs with high-performance garbage collection
* (every FJTask quickly becomes garbage) and good native thread support.
*
* Given these overhead savings, you might be tempted to use FJTasks for
* everything you would use a normal Thread to do. Don't. Java Threads
* remain better for general purpose thread-based programming. Remember
* that FJTasks cannot be used for designs involving arbitrary blocking
* synchronization or I/O. Extending FJTasks to support such capabilities
* would amount to re-inventing the Thread class, and would make them
* less optimal in the contexts that they were designed for.
* [ Introduction to this package. ]
*
* @see FJTaskRunner
* @see FJTaskRunnerGroup
**/
public abstract class FJTask implements Runnable {
/**
* The only status information associated with FJTasks is whether
* the they are considered to have completed.
* It is set true automatically within
* FJTaskRunner methods upon completion
* of the run method, or manually via cancel.
**/
private volatile boolean done; // = false;
/**
* Return the FJTaskRunner thread running the current FJTask.
* Most FJTask methods are just relays to their current
* FJTaskRunners, that perform the indicated actions.
* @exception ClassCastException if caller thread is not a
* running FJTask.
**/
public static FJTaskRunner getFJTaskRunner() {
return (FJTaskRunner)(Thread.currentThread());
}
/**
* Return the FJTaskRunnerGroup of the thread running the current FJTask.
* @exception ClassCastException if caller thread is not a
* running FJTask.
**/
public static FJTaskRunnerGroup getFJTaskRunnerGroup() {
return getFJTaskRunner().getGroup();
}
/**
* Return true if current task has terminated or been cancelled.
* The method is a simple analog of the Thread.isAlive()
* method. However, it reports true only when the task has terminated
* or has been cancelled. It does not distinguish these two cases.
* And there is no way to determine whether a FJTask has been started
* or is currently executing.
**/
public final boolean isDone() { return done; }
/**
* Indicate termination. Intended only to be called by FJTaskRunner.
* FJTasks themselves should use (non-final) method
* cancel() to suppress execution.
**/
protected final void setDone() { done = true; }
/**
* Set the termination status of this task. This simple-minded
* analog of Thread.interrupt
* causes the task not to execute if it has not already been started.
* Cancelling a running FJTask
* has no effect unless the run method itself uses isDone()
* to probe cancellation and take appropriate action.
* Individual run() methods may sense status and
* act accordingly, normally by returning early.
**/
public void cancel() { setDone(); }
/**
* Clear the termination status of this task.
* This method is intended to be used
* only as a means to allow task objects to be recycled. It should
* be called only when you are sure that the previous
* execution of this task has terminated and, if applicable, has
* been joined by all other waiting tasks. Usage in any other
* context is a very bad idea.
**/
public void reset() { done = false; }
/**
* Execute this task. This method merely places the task in a
* group-wide scheduling queue.
* It will be run
* the next time any TaskRunner thread is otherwise idle.
* This scheduling maintains FIFO ordering of started tasks
* with respect to
* the group of worker threads.
* @exception ClassCastException if caller thread is not
* running in a FJTaskRunner thread.
**/
public void start() { getFJTaskRunnerGroup().executeTask(this); }
/**
* Arrange for execution of a strictly dependent task.
* The task that will be executed in
* procedure-call-like LIFO order if executed by the
* same worker thread, but is FIFO with respect to other tasks
* forked by this thread when taken by other worker threads.
* That is, earlier-forked
* tasks are preferred to later-forked tasks by other idle workers.
*
* Fork() is noticeably
* faster than start(). However, it may only
* be used for strictly dependent tasks -- generally, those that
* could logically be issued as straight method calls without
* changing the logic of the program.
* The method is optimized for use in parallel fork/join designs
* in which the thread that issues one or more forks
* cannot continue until at least some of the forked
* threads terminate and are joined.
* @exception ClassCastException if caller thread is not
* running in a FJTaskRunner thread.
**/
public void fork() { getFJTaskRunner().push(this); }
/**
* Allow the current underlying FJTaskRunner thread to process other tasks.
*
* Spinloops based on yield() are well behaved so long
* as the event or condition being waited for is produced via another
* FJTask. Additionally, you must never hold a lock
* while performing a yield or join. (This is because
* multiple FJTasks can be run by the same Thread during
* a yield. Since java locks are held per-thread, the lock would not
* maintain the conceptual exclusion you have in mind.)
*
* Otherwise, spinloops using
* yield are the main construction of choice when a task must wait
* for a condition that it is sure will eventually occur because it
* is being produced by some other FJTask. The most common
* such condition is built-in: join() repeatedly yields until a task
* has terminated after producing some needed results. You can also
* use yield to wait for callbacks from other FJTasks, to wait for
* status flags to be set, and so on. However, in all these cases,
* you should be confident that the condition being waited for will
* occur, essentially always because it is produced by
* a FJTask generated by the current task, or one of its subtasks.
*
* @exception ClassCastException if caller thread is not
* running in a FJTaskRunner thread.
**/
public static void yield() { getFJTaskRunner().taskYield(); }
/**
* Yield until this task isDone.
* Equivalent to
* [ Introduction to this package. ]
**/
public class SynchronizedRef extends SynchronizedVariable {
/** The maintained reference **/
protected Object value_;
/**
* Create a SynchronizedRef initially holding the given reference
* and using its own internal lock.
**/
public SynchronizedRef(Object initialValue) {
super();
value_ = initialValue;
}
/**
* Make a new SynchronizedRef with the given initial value,
* and using the supplied lock.
**/
public SynchronizedRef(Object initialValue, Object lock) {
super(lock);
value_ = initialValue;
}
/**
* Return the current value
**/
public final Object get() { synchronized(lock_) { return value_; } }
/**
* Set to newValue.
* @return the old value
**/
public Object set(Object newValue) {
synchronized (lock_) {
Object old = value_;
value_ = newValue;
return old;
}
}
/**
* Set value to newValue only if it is currently assumedValue.
* @return true if successful
**/
public boolean commit(Object assumedValue, Object newValue) {
synchronized(lock_) {
boolean success = (assumedValue == value_);
if (success) value_ = newValue;
return success;
}
}
/**
* Atomically swap values with another SynchronizedRef.
* Uses identityHashCode to avoid deadlock when
* two SynchronizedRefs attempt to simultaneously swap with each other.
* (Note: Ordering via identyHashCode is not strictly guaranteed
* by the language specification to return unique, orderable
* values, but in practice JVMs rely on them being unique.)
* @return the new value
**/
public Object swap(SynchronizedRef other) {
if (other == this) return get();
SynchronizedRef fst = this;
SynchronizedRef snd = other;
if (System.identityHashCode(fst) > System.identityHashCode(snd)) {
fst = other;
snd = this;
}
synchronized(fst.lock_) {
synchronized(snd.lock_) {
fst.set(snd.set(fst.get()));
return get();
}
}
}
}
concurrent-dfsg-1.3.4/QueuedExecutor.java 0000644 0001750 0001750 00000014357 10202157355 020670 0 ustar wbaer wbaer 0000000 0000000 /*
File: QueuedExecutor.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
21Jun1998 dl Create public version
28aug1998 dl rely on ThreadFactoryUser, restart now public
4may1999 dl removed redundant interrupt detect
7sep2000 dl new shutdown methods
20may2004 dl can shutdown even if thread not created yet
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
*
* An implementation of Executor that queues incoming
* requests until they can be processed by a single background
* thread.
*
* The thread is not actually started until the first
*
* Beware that, especially in situations
* where command objects themselves invoke execute, queuing can
* sometimes lead to lockups, since commands that might allow
* other threads to terminate do not run at all when they are in the queue.
* [ Introduction to this package. ]
**/
public class QueuedExecutor extends ThreadFactoryUser implements Executor {
/** The thread used to process commands **/
protected Thread thread_;
/** Special queue element to signal termination **/
protected static Runnable ENDTASK = new Runnable() { public void run() {} };
/** true if thread should shut down after processing current task **/
protected volatile boolean shutdown_; // latches true;
/**
* Return the thread being used to process commands, or
* null if there is no such thread. You can use this
* to invoke any special methods on the thread, for
* example, to interrupt it.
**/
public synchronized Thread getThread() {
return thread_;
}
/** set thread_ to null to indicate termination **/
protected synchronized void clearThread() {
thread_ = null;
}
/** The queue **/
protected final Channel queue_;
/**
* The runloop is isolated in its own Runnable class
* just so that the main
* class need not implement Runnable, which would
* allow others to directly invoke run, which would
* never make sense here.
**/
protected class RunLoop implements Runnable {
public void run() {
try {
while (!shutdown_) {
Runnable task = (Runnable)(queue_.take());
if (task == ENDTASK) {
shutdown_ = true;
break;
}
else if (task != null) {
task.run();
task = null;
}
else
break;
}
}
catch (InterruptedException ex) {} // fallthrough
finally {
clearThread();
}
}
}
protected final RunLoop runLoop_;
/**
* Construct a new QueuedExecutor that uses
* the supplied Channel as its queue.
*
* This class does not support any methods that
* reveal this queue. If you need to access it
* independently (for example to invoke any
* special status monitoring operations), you
* should record a reference to it separately.
**/
public QueuedExecutor(Channel queue) {
queue_ = queue;
runLoop_ = new RunLoop();
}
/**
* Construct a new QueuedExecutor that uses
* a BoundedLinkedQueue with the current
* DefaultChannelCapacity as its queue.
**/
public QueuedExecutor() {
this(new BoundedLinkedQueue());
}
/**
* Start (or restart) the background thread to process commands. It has
* no effect if a thread is already running. This
* method can be invoked if the background thread crashed
* due to an unrecoverable exception.
**/
public synchronized void restart() {
if (thread_ == null && !shutdown_) {
thread_ = threadFactory_.newThread(runLoop_);
thread_.start();
}
}
/**
* Arrange for execution of the command in the
* background thread by adding it to the queue.
* The method may block if the channel's put
* operation blocks.
*
* If the background thread
* does not exist, it is created and started.
**/
public void execute(Runnable command) throws InterruptedException {
restart();
queue_.put(command);
}
/**
* Terminate background thread after it processes all
* elements currently in queue. Any tasks entered after this point will
* not be processed. A shut down thread cannot be restarted.
* This method may block if the task queue is finite and full.
* Also, this method
* does not in general apply (and may lead to comparator-based
* exceptions) if the task queue is a priority queue.
**/
public synchronized void shutdownAfterProcessingCurrentlyQueuedTasks() {
if (!shutdown_) {
try { queue_.put(ENDTASK); }
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
/**
* Terminate background thread after it processes the
* current task, removing other queued tasks and leaving them unprocessed.
* A shut down thread cannot be restarted.
**/
public synchronized void shutdownAfterProcessingCurrentTask() {
shutdown_ = true;
try {
while (queue_.poll(0) != null) ; // drain
queue_.put(ENDTASK);
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
/**
* Terminate background thread even if it is currently processing
* a task. This method uses Thread.interrupt, so relies on tasks
* themselves responding appropriately to interruption. If the
* current tasks does not terminate on interruption, then the
* thread will not terminate until processing current task.
* A shut down thread cannot be restarted.
**/
public synchronized void shutdownNow() {
shutdown_ = true;
Thread t = thread_;
if (t != null)
t.interrupt();
shutdownAfterProcessingCurrentTask();
}
}
concurrent-dfsg-1.3.4/intro.html 0000644 0001750 0001750 00000162376 10202157355 017104 0 ustar wbaer wbaer 0000000 0000000
Note: Upon release of J2SE 1.5, this package enters maintenance mode:
Only essential corrections will be released. JDK1.5 package
java.util.concurrent includes improved, more efficient,
standardized versions of the main components in this package. Please
plan to convert your applications to use them. (A few niche classes
here have no equivalents in java.util.concurrent. They will become
part of a follow-up add-on package that will also include other
unstandardized classes.)
This package provides standardized, efficient versions of utility
classes commonly encountered in concurrent Java programming. This
code consists of implementations of ideas that have been around for
ages, and is merely intended to save you the trouble of coding them.
Discussions of the rationale and applications of several of these
classes can be found in the second edition of Concurrent Programming in
Java. There are also pdf
slides providing an overview of the package.
The package mainly consists of implementations of a few interfaces:
If you arrived at page
It is currently distributed in source form only. To build it, use a
Java 1.2+ compiler to:
The classes in the
To use it, add to java files:
You can also create a jar or zip file of the compiled classes
and add them to your classpath.
All documentation
except for this file was produced by javadoc, which
places some index and summary files outside the current
directory. This can cause some broken links on unpacked versions.
You can avoid this, and integrate with your local javadoc-produced
documentation by running:
Implementations
The following implementation classes do not themselves perform any
synchronization, but serve as adaptors, glue, and extensibility
hooks for those that do. They may also be helpful when using Syncs
in generic before/after constructions:
Related Classes
Implementations
Implementations
Related Classes
Implementations
Related Classes
Implementations
Related classes
Konstantin Läufer has generously placed a version compiled for JDK1.1
at http://www.cs.luc.edu/~laufer/courses/337/handouts/concurrent11.zip
If you need to invoke such methods even when the thread is in an
interrupted state (for example, during recovery actions) you can do:
The heavy use of InterruptedException makes it possible to write
very responsive and robust code, at the expense of forcing class
and method authors to contemplate possible exception handling
actions at each interruption (and time-out) point. See the CPJ supplement
page on cancellation for more discussion of some associated
design issues.
You will almost surely trade off some cost in efficiency for the
flexibility of using Syncs and classes built out of them rather
than built-in
[ Introduction to this package. ]
**/
public class ReentrantLock implements Sync {
protected Thread owner_ = null;
protected long holds_ = 0;
public void acquire() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
Thread caller = Thread.currentThread();
synchronized(this) {
if (caller == owner_)
++holds_;
else {
try {
while (owner_ != null) wait();
owner_ = caller;
holds_ = 1;
}
catch (InterruptedException ex) {
notify();
throw ex;
}
}
}
}
public boolean attempt(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
Thread caller = Thread.currentThread();
synchronized(this) {
if (caller == owner_) {
++holds_;
return true;
}
else if (owner_ == null) {
owner_ = caller;
holds_ = 1;
return true;
}
else if (msecs <= 0)
return false;
else {
long waitTime = msecs;
long start = System.currentTimeMillis();
try {
for (;;) {
wait(waitTime);
if (caller == owner_) {
++holds_;
return true;
}
else if (owner_ == null) {
owner_ = caller;
holds_ = 1;
return true;
}
else {
waitTime = msecs - (System.currentTimeMillis() - start);
if (waitTime <= 0)
return false;
}
}
}
catch (InterruptedException ex) {
notify();
throw ex;
}
}
}
}
/**
* Release the lock.
* @exception Error thrown if not current owner of lock
**/
public synchronized void release() {
if (Thread.currentThread() != owner_)
throw new Error("Illegal Lock usage");
if (--holds_ == 0) {
owner_ = null;
notify();
}
}
/**
* Release the lock N times.
* @exception Error thrown if not current owner of lock
* or has fewer than N holds on the lock
**/
public synchronized void release(long n) {
if (Thread.currentThread() != owner_ || n > holds_)
throw new Error("Illegal Lock usage");
holds_ -= n;
if (holds_ == 0) {
owner_ = null;
notify();
}
}
/**
* Return the number of unreleased acquires performed
* by the current thread.
* Returns zero if current thread does not hold lock.
**/
public synchronized long holds() {
if (Thread.currentThread() != owner_) return 0;
return holds_;
}
}
concurrent-dfsg-1.3.4/CondVar.java 0000644 0001750 0001750 00000016451 10202157355 017252 0 ustar wbaer wbaer 0000000 0000000 /*
File: ConditionVariable.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* This class is designed for fans of POSIX pthreads programming.
* If you restrict yourself to Mutexes and CondVars, you can
* use most of your favorite constructions. Don't randomly mix them
* with synchronized methods or blocks though.
*
* Method names and behavior are as close as is reasonable to
* those in POSIX.
*
* Sample Usage. Here is a full version of a bounded buffer
* that implements the BoundedChannel interface, written in
* a style reminscent of that in POSIX programming books.
* [ Introduction to this package. ]
**/
public class CondVar {
/** The mutex **/
protected final Sync mutex_;
/**
* Create a new CondVar that relies on the given mutual
* exclusion lock.
* @param mutex A non-reentrant mutual exclusion lock.
* Standard usage is to supply an instance of
* This implementation makes no attempt to provide any fairness
* or ordering guarantees. If you need them, consider using one of
* the Semaphore implementations as a locking mechanism.
*
* Sample usage
* Mutex can be useful in constructions that cannot be
* expressed using java synchronized blocks because the
* acquire/release pairs do not occur in the same method or
* code block. For example, you can use them for hand-over-hand
* locking across the nodes of a linked list. This allows
* extremely fine-grained locking, and so increases
* potential concurrency, at the cost of additional complexity and
* overhead that would normally make this worthwhile only in cases of
* extreme contention.
*
* @see Semaphore
* [ Introduction to this package. ]
**/
public class Mutex implements Sync {
/** The lock status **/
protected boolean inuse_ = false;
public void acquire() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
synchronized(this) {
try {
while (inuse_) wait();
inuse_ = true;
}
catch (InterruptedException ex) {
notify();
throw ex;
}
}
}
public synchronized void release() {
inuse_ = false;
notify();
}
public boolean attempt(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
synchronized(this) {
if (!inuse_) {
inuse_ = true;
return true;
}
else if (msecs <= 0)
return false;
else {
long waitTime = msecs;
long start = System.currentTimeMillis();
try {
for (;;) {
wait(waitTime);
if (!inuse_) {
inuse_ = true;
return true;
}
else {
waitTime = msecs - (System.currentTimeMillis() - start);
if (waitTime <= 0)
return false;
}
}
}
catch (InterruptedException ex) {
notify();
throw ex;
}
}
}
}
}
concurrent-dfsg-1.3.4/Takable.java 0000644 0001750 0001750 00000004414 10202157355 017255 0 ustar wbaer wbaer 0000000 0000000 /*
File: Takable.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* This interface exists to enable stricter type checking
* for channels. A method argument or instance variable
* in a consumer object can be declared as only a Takable
* rather than a Channel, in which case a Java compiler
* will disallow put operations.
*
* Full method descriptions appear in the Channel interface.
* [ Introduction to this package. ]
* @see Channel
* @see Puttable
**/
public interface Takable {
/**
* Return and remove an item from channel,
* possibly waiting indefinitely until
* such an item exists.
* @return some item from the channel. Different implementations
* may guarantee various properties (such as FIFO) about that item
* @exception InterruptedException if the current thread has
* been interrupted at a point at which interruption
* is detected, in which case state of the channel is unchanged.
*
**/
public Object take() throws InterruptedException;
/**
* Return and remove an item from channel only if one is available within
* msecs milliseconds. The time bound is interpreted in a coarse
* grained, best-effort fashion.
* @param msecs the number of milliseconds to wait. If less than
* or equal to zero, the operation does not perform any timed waits,
* but might still require
* access to a synchronization lock, which can impose unbounded
* delay if there is a lot of contention for the channel.
* @return some item, or null if the channel is empty.
* @exception InterruptedException if the current thread has
* been interrupted at a point at which interruption
* is detected, in which case state of the channel is unchanged
* (i.e., equivalent to a false return).
**/
public Object poll(long msecs) throws InterruptedException;
}
concurrent-dfsg-1.3.4/FJTaskRunner.java 0000644 0001750 0001750 00000070711 10202157355 020231 0 ustar wbaer wbaer 0000000 0000000 /*
File: FJTaskRunner.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
7Jan1999 dl First public release
13Jan1999 dl correct a stat counter update;
ensure inactive status on run termination;
misc minor cleaup
14Jan1999 dl Use random starting point in scan;
variable renamings.
18Jan1999 dl Runloop allowed to die on task exception;
remove useless timed join
22Jan1999 dl Rework scan to allow use of priorities.
6Feb1999 dl Documentation updates.
7Mar1999 dl Add array-based coInvoke
31Mar1999 dl Revise scan to remove need for NullTasks
27Apr1999 dl Renamed
23oct1999 dl Earlier detect of interrupt in scanWhileIdling
24nov1999 dl Now works on JVMs that do not properly
implement read-after-write of 2 volatiles.
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.util.Random;
/**
* Specialized Thread subclass for running FJTasks.
*
* Each FJTaskRunner keeps FJTasks in a double-ended queue (DEQ).
* Double-ended queues support stack-based operations
* push and pop, as well as queue-based operations put and take.
* Normally, threads run their own tasks. But they
* may also steal tasks from each others DEQs.
*
* The algorithms are minor variants of those used
* in Cilk and
* Hood, and
* to a lesser extent
* Filaments,
* but are adapted to work in Java.
*
* The two most important capabilities are:
*
* Implementations of the underlying representations and operations
* are geared for use on JVMs operating on multiple CPUs (although
* they should of course work fine on single CPUs as well).
*
* A possible snapshot of a FJTaskRunner's DEQ is:
*
* FJTasks are held in elements of the DEQ.
* They are maintained in a bounded array that
* works similarly to a circular bounded buffer. To ensure
* visibility of stolen FJTasks across threads, the array elements
* must be
* However, since there is no way
* to declare an array of volatiles in Java, the DEQ elements actually
* hold VolatileTaskRef objects, each of which in turn holds a
* volatile reference to a FJTask.
* Even with the double-indirection overhead of
* volatile refs, using an array for the DEQ works out
* better than linking them since fewer shared
* memory locations need to be
* touched or modified by the threads while using the DEQ.
* Further, the double indirection may alleviate cache-line
* sharing effects (which cannot otherwise be directly dealt with in Java).
*
* The indices for the
* A push operation can normally run concurrently with a steal.
* A push enters a synch lock only if the DEQ appears full so must
* either be resized or have indices adjusted due to wrap-around
* of the bounded DEQ. The put operation always requires synchronization.
*
* When a FJTaskRunner thread has no tasks of its own to run,
* it tries to be a good citizen.
* Threads run at lower priority while scanning for work.
*
* If the task is currently waiting
* via yield, the thread alternates scans (starting at a randomly
* chosen victim) with Thread.yields. This is
* well-behaved so long as the JVM handles Thread.yield in a
* sensible fashion. (It need not. Thread.yield is so underspecified
* that it is legal for a JVM to treat it as a no-op.) This also
* keeps things well-behaved even if we are running on a uniprocessor
* JVM using a simple cooperative threading model.
*
* If a thread needing work is
* is otherwise idle (which occurs only in the main runloop), and
* there are no available tasks to steal or poll, it
* instead enters into a sleep-based (actually timed wait(msec))
* phase in which it progressively sleeps for longer durations
* (up to a maximum of FJTaskRunnerGroup.MAX_SLEEP_TIME,
* currently 100ms) between scans.
* If all threads in the group
* are idling, they further progress to a hard wait phase, suspending
* until a new task is entered into the FJTaskRunnerGroup entry queue.
* A sleeping FJTaskRunner thread may be awakened by a new
* task being put into the group entry queue or by another FJTaskRunner
* becoming active, but not merely by some DEQ becoming non-empty.
* Thus the MAX_SLEEP_TIME provides a bound for sleep durations
* in cases where all but one worker thread start sleeping
* even though there will eventually be work produced
* by a thread that is taking a long time to place tasks in DEQ.
* These sleep mechanics are handled in the FJTaskRunnerGroup class.
*
* Composite operations such as taskJoin include heavy
* manual inlining of the most time-critical operations
* (mainly FJTask.invoke).
* This opens up a few opportunities for further hand-optimizations.
* Until Java compilers get a lot smarter, these tweaks
* improve performance significantly enough for task-intensive
* programs to be worth the poorer maintainability and code duplication.
*
* Because they are so fragile and performance-sensitive, nearly
* all methods are declared as final. However, nearly all fields
* and methods are also declared as protected, so it is possible,
* with much care, to extend functionality in subclasses. (Normally
* you would also need to subclass FJTaskRunnerGroup.)
*
* None of the normal java.lang.Thread class methods should ever be called
* on FJTaskRunners. For this reason, it might have been nicer to
* declare FJTaskRunner as a Runnable to run within a Thread. However,
* this would have complicated many minor logistics. And since
* no FJTaskRunner methods should normally be called from outside the
* FJTask and FJTaskRunnerGroup classes either, this decision doesn't impact
* usage.
*
* You might think that layering this kind of framework on top of
* Java threads, which are already several levels removed from raw CPU
* scheduling on most systems, would lead to very poor performance.
* But on the platforms
* tested, the performance is quite good.
* [ Introduction to this package. ]
* @see FJTask
* @see FJTaskRunnerGroup
**/
public class FJTaskRunner extends Thread {
/** The group of which this FJTaskRunner is a member **/
protected final FJTaskRunnerGroup group;
/**
* Constructor called only during FJTaskRunnerGroup initialization
**/
protected FJTaskRunner(FJTaskRunnerGroup g) {
group = g;
victimRNG = new Random(System.identityHashCode(this));
runPriority = getPriority();
setDaemon(true);
}
/**
* Return the FJTaskRunnerGroup of which this thread is a member
**/
protected final FJTaskRunnerGroup getGroup() { return group; }
/* ------------ DEQ Representation ------------------- */
/**
* FJTasks are held in an array-based DEQ with INITIAL_CAPACITY
* elements. The DEQ is grown if necessary, but default value is
* normally much more than sufficient unless there are
* user programming errors or questionable operations generating
* large numbers of Tasks without running them.
* Capacities must be a power of two.
**/
protected static final int INITIAL_CAPACITY = 4096;
/**
* The maximum supported DEQ capacity.
* When exceeded, FJTaskRunner operations throw Errors
**/
protected static final int MAX_CAPACITY = 1 << 30;
/**
* An object holding a single volatile reference to a FJTask.
**/
protected final static class VolatileTaskRef {
/** The reference **/
protected volatile FJTask ref;
/** Set the reference **/
protected final void put(FJTask r) { ref = r; }
/** Return the reference **/
protected final FJTask get() { return ref; }
/** Return the reference and clear it **/
protected final FJTask take() { FJTask r = ref; ref = null; return r; }
/**
* Initialization utility for constructing arrays.
* Make an array of given capacity and fill it with
* VolatileTaskRefs.
**/
protected static VolatileTaskRef[] newArray(int cap) {
VolatileTaskRef[] a = new VolatileTaskRef[cap];
for (int k = 0; k < cap; k++) a[k] = new VolatileTaskRef();
return a;
}
}
/**
* The DEQ array.
**/
protected VolatileTaskRef[] deq = VolatileTaskRef.newArray(INITIAL_CAPACITY);
/** Current size of the task DEQ **/
protected int deqSize() { return deq.length; }
/**
* Current top of DEQ. Generally acts just like a stack pointer in an
* array-based stack, except that it circularly wraps around the
* array, as in an array-based queue. The value is NOT
* always kept within
* This is not usually called directly but is
* instead inlined in callers. This version differs from the
* cilk algorithm in that pop does not fully back down and
* retry in the case of potential conflict with take. It simply
* rechecks under synch lock. This gives a preference
* for threads to run their own tasks, which seems to
* reduce flailing a bit when there are few tasks to run.
**/
protected final FJTask pop() {
/*
Decrement top, to force a contending take to back down.
*/
int t = --top;
/*
To avoid problems with JVMs that do not properly implement
read-after-write of a pair of volatiles, we conservatively
grab without lock only if the DEQ appears to have at least two
elements, thus guaranteeing that both a pop and take will succeed,
even if the pre-increment in take is not seen by current thread.
Otherwise we recheck under synch.
*/
if (base + 1 < t)
return deq[t & (deq.length-1)].take();
else
return confirmPop(t);
}
/**
* Check under synch lock if DEQ is really empty when doing pop.
* Return task if not empty, else null.
**/
protected final synchronized FJTask confirmPop(int provisionalTop) {
if (base <= provisionalTop)
return deq[provisionalTop & (deq.length-1)].take();
else { // was empty
/*
Reset DEQ indices to zero whenever it is empty.
This both avoids unnecessary calls to checkOverflow
in push, and helps keep the DEQ from accumulating garbage
*/
top = base = 0;
return null;
}
}
/**
* Take a task from the base of the DEQ.
* Always called by other threads via scan()
**/
protected final synchronized FJTask take() {
/*
Increment base in order to suppress a contending pop
*/
int b = base++;
if (b < top)
return confirmTake(b);
else {
// back out
base = b;
return null;
}
}
/**
* double-check a potential take
**/
protected FJTask confirmTake(int oldBase) {
/*
Use a second (guaranteed uncontended) synch
to serve as a barrier in case JVM does not
properly process read-after-write of 2 volatiles
*/
synchronized(barrier) {
if (oldBase < top) {
/*
We cannot call deq[oldBase].take here because of possible races when
nulling out versus concurrent push operations. Resulting
accumulated garbage is swept out periodically in
checkOverflow, or more typically, just by keeping indices
zero-based when found to be empty in pop, which keeps active
region small and constantly overwritten.
*/
return deq[oldBase & (deq.length-1)].get();
}
else {
base = oldBase;
return null;
}
}
}
/**
* Adjust top and base, and grow DEQ if necessary.
* Called only while DEQ synch lock being held.
* We don't expect this to be called very often. In most
* programs using FJTasks, it is never called.
**/
protected void checkOverflow() {
int t = top;
int b = base;
if (t - b < deq.length-1) { // check if just need an index reset
int newBase = b & (deq.length-1);
int newTop = top & (deq.length-1);
if (newTop < newBase) newTop += deq.length;
top = newTop;
base = newBase;
/*
Null out refs to stolen tasks.
This is the only time we can safely do it.
*/
int i = newBase;
while (i != newTop && deq[i].ref != null) {
deq[i].ref = null;
i = (i - 1) & (deq.length-1);
}
}
else { // grow by doubling array
int newTop = t - b;
int oldcap = deq.length;
int newcap = oldcap * 2;
if (newcap >= MAX_CAPACITY)
throw new Error("FJTask queue maximum capacity exceeded");
VolatileTaskRef[] newdeq = new VolatileTaskRef[newcap];
// copy in bottom half of new deq with refs from old deq
for (int j = 0; j < oldcap; ++j) newdeq[j] = deq[b++ & (oldcap-1)];
// fill top half of new deq with new refs
for (int j = oldcap; j < newcap; ++j) newdeq[j] = new VolatileTaskRef();
deq = newdeq;
base = 0;
top = newTop;
}
}
/* ------------ Scheduling ------------------- */
/**
* Do all but the pop() part of yield or join, by
* traversing all DEQs in our group looking for a task to
* steal. If none, it checks the entry queue.
*
* Since there are no good, portable alternatives,
* we rely here on a mixture of Thread.yield and priorities
* to reduce wasted spinning, even though these are
* not well defined. We are hoping here that the JVM
* does something sensible.
* @param waitingFor if non-null, the current task being joined
**/
protected void scan(final FJTask waitingFor) {
FJTask task = null;
// to delay lowering priority until first failure to steal
boolean lowered = false;
/*
Circularly traverse from a random start index.
This differs slightly from cilk version that uses a random index
for each attempted steal.
Exhaustive scanning might impede analytic tractablity of
the scheduling policy, but makes it much easier to deal with
startup and shutdown.
*/
FJTaskRunner[] ts = group.getArray();
int idx = victimRNG.nextInt(ts.length);
for (int i = 0; i < ts.length; ++i) {
FJTaskRunner t = ts[idx];
if (++idx >= ts.length) idx = 0; // circularly traverse
if (t != null && t != this) {
if (waitingFor != null && waitingFor.isDone()) {
break;
}
else {
if (COLLECT_STATS) ++scans;
task = t.take();
if (task != null) {
if (COLLECT_STATS) ++steals;
break;
}
else if (isInterrupted()) {
break;
}
else if (!lowered) { // if this is first fail, lower priority
lowered = true;
setPriority(scanPriority);
}
else { // otherwise we are at low priority; just yield
yield();
}
}
}
}
if (task == null) {
if (COLLECT_STATS) ++scans;
task = group.pollEntryQueue();
if (COLLECT_STATS) if (task != null) ++steals;
}
if (lowered) setPriority(runPriority);
if (task != null && !task.isDone()) {
if (COLLECT_STATS) ++runs;
task.run();
task.setDone();
}
}
/**
* Same as scan, but called when current thread is idling.
* It repeatedly scans other threads for tasks,
* sleeping while none are available.
*
* This differs from scan mainly in that
* since there is no reason to return to recheck any
* condition, we iterate until a task is found, backing
* off via sleeps if necessary.
**/
protected void scanWhileIdling() {
FJTask task = null;
boolean lowered = false;
long iters = 0;
FJTaskRunner[] ts = group.getArray();
int idx = victimRNG.nextInt(ts.length);
do {
for (int i = 0; i < ts.length; ++i) {
FJTaskRunner t = ts[idx];
if (++idx >= ts.length) idx = 0; // circularly traverse
if (t != null && t != this) {
if (COLLECT_STATS) ++scans;
task = t.take();
if (task != null) {
if (COLLECT_STATS) ++steals;
if (lowered) setPriority(runPriority);
group.setActive(this);
break;
}
}
}
if (task == null) {
if (isInterrupted())
return;
if (COLLECT_STATS) ++scans;
task = group.pollEntryQueue();
if (task != null) {
if (COLLECT_STATS) ++steals;
if (lowered) setPriority(runPriority);
group.setActive(this);
}
else {
++iters;
// Check here for yield vs sleep to avoid entering group synch lock
if (iters >= group.SCANS_PER_SLEEP) {
group.checkActive(this, iters);
if (isInterrupted())
return;
}
else if (!lowered) {
lowered = true;
setPriority(scanPriority);
}
else {
yield();
}
}
}
} while (task == null);
if (!task.isDone()) {
if (COLLECT_STATS) ++runs;
task.run();
task.setDone();
}
}
/* ------------ composite operations ------------------- */
/**
* Main runloop
**/
public void run() {
try{
while (!interrupted()) {
FJTask task = pop();
if (task != null) {
if (!task.isDone()) {
// inline FJTask.invoke
if (COLLECT_STATS) ++runs;
task.run();
task.setDone();
}
}
else
scanWhileIdling();
}
}
finally {
group.setInactive(this);
}
}
/**
* Execute a task in this thread. Generally called when current task
* cannot otherwise continue.
**/
protected final void taskYield() {
FJTask task = pop();
if (task != null) {
if (!task.isDone()) {
if (COLLECT_STATS) ++runs;
task.run();
task.setDone();
}
}
else
scan(null);
}
/**
* Process tasks until w is done.
* Equivalent to
* [ Introduction to this package. ]
**/
public interface ThreadFactory {
/**
* Create a new thread that will run the given command when started
**/
public Thread newThread(Runnable command);
}
concurrent-dfsg-1.3.4/Callable.java 0000644 0001750 0001750 00000002240 10202157355 017404 0 ustar wbaer wbaer 0000000 0000000
/*
File: Callable.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
30Jun1998 dl Create public version
5Jan1999 dl Change Exception to Throwable in call signature
27Jan1999 dl Undo last change
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* Interface for runnable actions that bear results and/or throw Exceptions.
* This interface is designed to provide a common protocol for
* result-bearing actions that can be run independently in threads,
* in which case
* they are ordinarily used as the bases of Runnables that set
* FutureResults
*
* [ Introduction to this package. ]
* @see FutureResult
**/
public interface Callable {
/** Perform some action that returns a result or throws an exception **/
Object call() throws Exception;
}
concurrent-dfsg-1.3.4/Channel.java 0000644 0001750 0001750 00000025373 10202157355 017271 0 ustar wbaer wbaer 0000000 0000000 /*
File: Channel.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
25aug1998 dl added peek
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* Main interface for buffers, queues, pipes, conduits, etc.
*
* A Channel represents anything that you can put items
* into and take them out of. As with the Sync
* interface, both
* blocking (put(x), take),
* and timeouts (offer(x, msecs), poll(msecs)) policies
* are provided. Using a
* zero timeout for offer and poll results in a pure balking policy.
*
* To aid in efforts to use Channels in a more typesafe manner,
* this interface extends Puttable and Takable. You can restrict
* arguments of instance variables to this type as a way of
* guaranteeing that producers never try to take, or consumers put.
* for example:
*
* A given channel implementation might or might not have bounded
* capacity or other insertion constraints, so in general, you cannot tell if
* a given put will block. However,
* Channels that are designed to
* have an element capacity (and so always block when full)
* should implement the
* BoundedChannel
* subinterface.
*
* Channels may hold any kind of item. However,
* insertion of null is not in general supported. Implementations
* may (all currently do) throw IllegalArgumentExceptions upon attempts to
* insert null.
*
* By design, the Channel interface does not support any methods to determine
* the current number of elements being held in the channel.
* This decision reflects the fact that in
* concurrent programming, such methods are so rarely useful
* that including them invites misuse; at best they could
* provide a snapshot of current
* state, that could change immediately after being reported.
* It is better practice to instead use poll and offer to try
* to take and put elements without blocking. For example,
* to empty out the current contents of a channel, you could write:
*
* However, it is possible to determine whether an item
* exists in a Channel via
* When appropriate, you can define an isEmpty method to
* return whether
* Also, as a compromise, even though it does not appear in interface,
* implementation classes that can readily compute the number
* of elements support a
* All channels allow multiple producers and/or consumers.
* They do not support any kind of close method
* to shut down operation or indicate completion of particular
* producer or consumer threads.
* If you need to signal completion, one way to do it is to
* create a class such as
*
* In time-out based methods (poll(msecs) and offer(x, msecs),
* time bounds are interpreted in
* a coarse-grained, best-effort fashion. Since there is no
* way in Java to escape out of a wait for a synchronized
* method/block, time bounds can sometimes be exceeded when
* there is a lot contention for the channel. Additionally,
* some Channel semantics entail a ``point of
* no return'' where, once some parts of the operation have completed,
* others must follow, regardless of time bound.
*
* Interruptions are in general handled as early as possible
* in all methods. Normally, InterruptionExceptions are thrown
* in put/take and offer(msec)/poll(msec) if interruption
* is detected upon entry to the method, as well as in any
* later context surrounding waits.
*
* If a put returns normally, an offer
* returns true, or a put or poll returns non-null, the operation
* completed successfully.
* In all other cases, the operation fails cleanly -- the
* element is not put or taken.
*
* As with Sync classes, spinloops are not directly supported,
* are not particularly recommended for routine use, but are not hard
* to construct. For example, here is an exponential backoff version:
*
* Sample Usage. Here is a producer/consumer design
* where the channel is used to hold Runnable commands representing
* background tasks.
* [ Introduction to this package. ]
* @see Sync
* @see BoundedChannel
**/
public interface Channel extends Puttable, Takable {
/**
* Place item in the channel, possibly waiting indefinitely until
* it can be accepted. Channels implementing the BoundedChannel
* subinterface are generally guaranteed to block on puts upon
* reaching capacity, but other implementations may or may not block.
* @param item the element to be inserted. Should be non-null.
* @exception InterruptedException if the current thread has
* been interrupted at a point at which interruption
* is detected, in which case the element is guaranteed not
* to be inserted. Otherwise, on normal return, the element is guaranteed
* to have been inserted.
**/
public void put(Object item) throws InterruptedException;
/**
* Place item in channel only if it can be accepted within
* msecs milliseconds. The time bound is interpreted in
* a coarse-grained, best-effort fashion.
* @param item the element to be inserted. Should be non-null.
* @param msecs the number of milliseconds to wait. If less than
* or equal to zero, the method does not perform any timed waits,
* but might still require
* access to a synchronization lock, which can impose unbounded
* delay if there is a lot of contention for the channel.
* @return true if accepted, else false
* @exception InterruptedException if the current thread has
* been interrupted at a point at which interruption
* is detected, in which case the element is guaranteed not
* to be inserted (i.e., is equivalent to a false return).
**/
public boolean offer(Object item, long msecs) throws InterruptedException;
/**
* Return and remove an item from channel,
* possibly waiting indefinitely until
* such an item exists.
* @return some item from the channel. Different implementations
* may guarantee various properties (such as FIFO) about that item
* @exception InterruptedException if the current thread has
* been interrupted at a point at which interruption
* is detected, in which case state of the channel is unchanged.
*
**/
public Object take() throws InterruptedException;
/**
* Return and remove an item from channel only if one is available within
* msecs milliseconds. The time bound is interpreted in a coarse
* grained, best-effort fashion.
* @param msecs the number of milliseconds to wait. If less than
* or equal to zero, the operation does not perform any timed waits,
* but might still require
* access to a synchronization lock, which can impose unbounded
* delay if there is a lot of contention for the channel.
* @return some item, or null if the channel is empty.
* @exception InterruptedException if the current thread has
* been interrupted at a point at which interruption
* is detected, in which case state of the channel is unchanged
* (i.e., equivalent to a null return).
**/
public Object poll(long msecs) throws InterruptedException;
/**
* Return, but do not remove object at head of Channel,
* or null if it is empty.
**/
public Object peek();
}
concurrent-dfsg-1.3.4/BoundedPriorityQueue.java 0000644 0001750 0001750 00000007755 10202157355 022054 0 ustar wbaer wbaer 0000000 0000000 /*
File: BoundedPriorityQueue.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
16Jun1998 dl Create public version
25aug1998 dl added peek
29aug1998 dl pulled heap mechanics into separate class
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.util.Comparator;
import java.lang.reflect.*;
/**
* A heap-based priority queue, using semaphores for
* concurrency control.
* The take operation returns the least element
* with respect to the given ordering. (If more than
* one element is tied for least value, one of them is
* arbitrarily chosen to be returned -- no guarantees
* are made for ordering across ties.)
* Ordering follows the JDK1.2 collection
* conventions: Either the elements must be Comparable, or
* a Comparator must be supplied. Comparison failures throw
* ClassCastExceptions during insertions and extractions.
* The implementation uses a standard array-based heap algorithm,
* as described in just about any data structures textbook.
*
* Put and take operations may throw ClassCastException
* if elements are not Comparable, or
* not comparable using the supplied comparator.
* Since not all elements are compared on each operation
* it is possible that an exception will not be thrown
* during insertion of non-comparable element, but will later be
* encountered during another insertion or extraction.
* [ Introduction to this package. ]
**/
public class BoundedPriorityQueue extends SemaphoreControlledChannel {
protected final Heap heap_;
/**
* Create a priority queue with the given capacity and comparator
* @exception IllegalArgumentException if capacity less or equal to zero
**/
public BoundedPriorityQueue(int capacity, Comparator cmp)
throws IllegalArgumentException {
super(capacity);
heap_ = new Heap(capacity, cmp);
}
/**
* Create a priority queue with the current default capacity
* and the given comparator
**/
public BoundedPriorityQueue(Comparator comparator) {
this(DefaultChannelCapacity.get(), comparator);
}
/**
* Create a priority queue with the given capacity,
* and relying on natural ordering.
**/
public BoundedPriorityQueue(int capacity) {
this(capacity, null);
}
/**
* Create a priority queue with the current default capacity
* and relying on natural ordering.
**/
public BoundedPriorityQueue() {
this(DefaultChannelCapacity.get(), null);
}
/**
* Create a priority queue with the given capacity and comparator, using
* the supplied Semaphore class for semaphores.
* @exception IllegalArgumentException if capacity less or equal to zero
* @exception NoSuchMethodException If class does not have constructor
* that intializes permits
* @exception SecurityException if constructor information
* not accessible
* @exception InstantiationException if semaphore class is abstract
* @exception IllegalAccessException if constructor cannot be called
* @exception InvocationTargetException if semaphore constructor throws an
* exception
**/
public BoundedPriorityQueue(int capacity, Comparator cmp,
Class semaphoreClass)
throws IllegalArgumentException,
NoSuchMethodException,
SecurityException,
InstantiationException,
IllegalAccessException,
InvocationTargetException {
super(capacity, semaphoreClass);
heap_ = new Heap(capacity, cmp);
}
protected void insert(Object x) { heap_.insert(x); }
protected Object extract() { return heap_.extract(); }
public Object peek() { return heap_.peek(); }
}
concurrent-dfsg-1.3.4/SynchronousChannel.java 0000644 0001750 0001750 00000024376 10202157355 021546 0 ustar wbaer wbaer 0000000 0000000 /*
File: SynchronousChannel.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
17Jul1998 dl Disabled direct semaphore permit check
31Jul1998 dl Replaced main algorithm with one with
better scaling and fairness properties.
25aug1998 dl added peek
24Nov2001 dl Replaced main algorithm with faster one.
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A rendezvous channel, similar to those used in CSP and Ada. Each
* put must wait for a take, and vice versa. Synchronous channels
* are well suited for handoff designs, in which an object running in
* one thread must synch up with an object running in another thread
* in order to hand it some information, event, or task.
* If you only need threads to synch up without
* exchanging information, consider using a Barrier. If you need
* bidirectional exchanges, consider using a Rendezvous.
*
* [ Introduction to this package. ]
* @see CyclicBarrier
* @see Rendezvous
**/
public class SynchronousChannel implements BoundedChannel {
/*
This implementation divides actions into two cases for puts:
* An arriving putter that does not already have a waiting taker
creates a node holding item, and then waits for a taker to take it.
* An arriving putter that does already have a waiting taker fills
the slot node created by the taker, and notifies it to continue.
And symmetrically, two for takes:
* An arriving taker that does not already have a waiting putter
creates an empty slot node, and then waits for a putter to fill it.
* An arriving taker that does already have a waiting putter takes
item from the node created by the putter, and notifies it to continue.
This requires keeping two simple queues: waitingPuts and waitingTakes.
When a put or take waiting for the actions of its counterpart
aborts due to interruption or timeout, it marks the node
it created as "CANCELLED", which causes its counterpart to retry
the entire put or take sequence.
*/
/**
* Special marker used in queue nodes to indicate that
* the thread waiting for a change in the node has timed out
* or been interrupted.
**/
protected static final Object CANCELLED = new Object();
/**
* Simple FIFO queue class to hold waiting puts/takes.
**/
protected static class Queue {
protected LinkedNode head;
protected LinkedNode last;
protected void enq(LinkedNode p) {
if (last == null)
last = head = p;
else
last = last.next = p;
}
protected LinkedNode deq() {
LinkedNode p = head;
if (p != null && (head = p.next) == null)
last = null;
return p;
}
}
protected final Queue waitingPuts = new Queue();
protected final Queue waitingTakes = new Queue();
/**
* @return zero --
* Synchronous channels have no internal capacity.
**/
public int capacity() { return 0; }
/**
* @return null --
* Synchronous channels do not hold contents unless actively taken
**/
public Object peek() { return null; }
public void put(Object x) throws InterruptedException {
if (x == null) throw new IllegalArgumentException();
// This code is conceptually straightforward, but messy
// because we need to intertwine handling of put-arrives first
// vs take-arrives first cases.
// Outer loop is to handle retry due to cancelled waiting taker
for (;;) {
// Get out now if we are interrupted
if (Thread.interrupted()) throw new InterruptedException();
// Exactly one of item or slot will be nonnull at end of
// synchronized block, depending on whether a put or a take
// arrived first.
LinkedNode slot;
LinkedNode item = null;
synchronized(this) {
// Try to match up with a waiting taker; fill and signal it below
slot = waitingTakes.deq();
// If no takers yet, create a node and wait below
if (slot == null)
waitingPuts.enq(item = new LinkedNode(x));
}
if (slot != null) { // There is a waiting taker.
// Fill in the slot created by the taker and signal taker to
// continue.
synchronized(slot) {
if (slot.value != CANCELLED) {
slot.value = x;
slot.notify();
return;
}
// else the taker has cancelled, so retry outer loop
}
}
else {
// Wait for a taker to arrive and take the item.
synchronized(item) {
try {
while (item.value != null)
item.wait();
return;
}
catch (InterruptedException ie) {
// If item was taken, return normally but set interrupt status
if (item.value == null) {
Thread.currentThread().interrupt();
return;
}
else {
item.value = CANCELLED;
throw ie;
}
}
}
}
}
}
public Object take() throws InterruptedException {
// Entirely symmetric to put()
for (;;) {
if (Thread.interrupted()) throw new InterruptedException();
LinkedNode item;
LinkedNode slot = null;
synchronized(this) {
item = waitingPuts.deq();
if (item == null)
waitingTakes.enq(slot = new LinkedNode());
}
if (item != null) {
synchronized(item) {
Object x = item.value;
if (x != CANCELLED) {
item.value = null;
item.next = null;
item.notify();
return x;
}
}
}
else {
synchronized(slot) {
try {
for (;;) {
Object x = slot.value;
if (x != null) {
slot.value = null;
slot.next = null;
return x;
}
else
slot.wait();
}
}
catch(InterruptedException ie) {
Object x = slot.value;
if (x != null) {
slot.value = null;
slot.next = null;
Thread.currentThread().interrupt();
return x;
}
else {
slot.value = CANCELLED;
throw ie;
}
}
}
}
}
}
/*
Offer and poll are just like put and take, except even messier.
*/
public boolean offer(Object x, long msecs) throws InterruptedException {
if (x == null) throw new IllegalArgumentException();
long waitTime = msecs;
long startTime = 0; // lazily initialize below if needed
for (;;) {
if (Thread.interrupted()) throw new InterruptedException();
LinkedNode slot;
LinkedNode item = null;
synchronized(this) {
slot = waitingTakes.deq();
if (slot == null) {
if (waitTime <= 0)
return false;
else
waitingPuts.enq(item = new LinkedNode(x));
}
}
if (slot != null) {
synchronized(slot) {
if (slot.value != CANCELLED) {
slot.value = x;
slot.notify();
return true;
}
}
}
long now = System.currentTimeMillis();
if (startTime == 0)
startTime = now;
else
waitTime = msecs - (now - startTime);
if (item != null) {
synchronized(item) {
try {
for (;;) {
if (item.value == null)
return true;
if (waitTime <= 0) {
item.value = CANCELLED;
return false;
}
item.wait(waitTime);
waitTime = msecs - (System.currentTimeMillis() - startTime);
}
}
catch (InterruptedException ie) {
if (item.value == null) {
Thread.currentThread().interrupt();
return true;
}
else {
item.value = CANCELLED;
throw ie;
}
}
}
}
}
}
public Object poll(long msecs) throws InterruptedException {
long waitTime = msecs;
long startTime = 0;
for (;;) {
if (Thread.interrupted()) throw new InterruptedException();
LinkedNode item;
LinkedNode slot = null;
synchronized(this) {
item = waitingPuts.deq();
if (item == null) {
if (waitTime <= 0)
return null;
else
waitingTakes.enq(slot = new LinkedNode());
}
}
if (item != null) {
synchronized(item) {
Object x = item.value;
if (x != CANCELLED) {
item.value = null;
item.next = null;
item.notify();
return x;
}
}
}
long now = System.currentTimeMillis();
if (startTime == 0)
startTime = now;
else
waitTime = msecs - (now - startTime);
if (slot != null) {
synchronized(slot) {
try {
for (;;) {
Object x = slot.value;
if (x != null) {
slot.value = null;
slot.next = null;
return x;
}
if (waitTime <= 0) {
slot.value = CANCELLED;
return null;
}
slot.wait(waitTime);
waitTime = msecs - (System.currentTimeMillis() - startTime);
}
}
catch(InterruptedException ie) {
Object x = slot.value;
if (x != null) {
slot.value = null;
slot.next = null;
Thread.currentThread().interrupt();
return x;
}
else {
slot.value = CANCELLED;
throw ie;
}
}
}
}
}
}
}
concurrent-dfsg-1.3.4/SynchronizedBoolean.java 0000644 0001750 0001750 00000010165 10202157355 021671 0 ustar wbaer wbaer 0000000 0000000 /*
File: SynchronizedBoolean.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
19Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A class useful for offloading synch for boolean instance variables.
*
* [ Introduction to this package. ]
**/
public class SynchronizedBoolean extends SynchronizedVariable implements Comparable, Cloneable {
protected boolean value_;
/**
* Make a new SynchronizedBoolean with the given initial value,
* and using its own internal lock.
**/
public SynchronizedBoolean(boolean initialValue) {
super();
value_ = initialValue;
}
/**
* Make a new SynchronizedBoolean with the given initial value,
* and using the supplied lock.
**/
public SynchronizedBoolean(boolean initialValue, Object lock) {
super(lock);
value_ = initialValue;
}
/**
* Return the current value
**/
public final boolean get() { synchronized(lock_) { return value_; } }
/**
* Set to newValue.
* @return the old value
**/
public boolean set(boolean newValue) {
synchronized (lock_) {
boolean old = value_;
value_ = newValue;
return old;
}
}
/**
* Set value to newValue only if it is currently assumedValue.
* @return true if successful
**/
public boolean commit(boolean assumedValue, boolean newValue) {
synchronized(lock_) {
boolean success = (assumedValue == value_);
if (success) value_ = newValue;
return success;
}
}
/**
* Atomically swap values with another SynchronizedBoolean.
* Uses identityHashCode to avoid deadlock when
* two SynchronizedBooleans attempt to simultaneously swap with each other.
* (Note: Ordering via identyHashCode is not strictly guaranteed
* by the language specification to return unique, orderable
* values, but in practice JVMs rely on them being unique.)
* @return the new value
**/
public boolean swap(SynchronizedBoolean other) {
if (other == this) return get();
SynchronizedBoolean fst = this;
SynchronizedBoolean snd = other;
if (System.identityHashCode(fst) > System.identityHashCode(snd)) {
fst = other;
snd = this;
}
synchronized(fst.lock_) {
synchronized(snd.lock_) {
fst.set(snd.set(fst.get()));
return get();
}
}
}
/**
* Set the value to its complement
* @return the new value
**/
public boolean complement() {
synchronized (lock_) {
value_ = !value_;
return value_;
}
}
/**
* Set value to value & b.
* @return the new value
**/
public boolean and(boolean b) {
synchronized (lock_) {
value_ = value_ & b;
return value_;
}
}
/**
* Set value to value | b.
* @return the new value
**/
public boolean or(boolean b) {
synchronized (lock_) {
value_ = value_ | b;
return value_;
}
}
/**
* Set value to value ^ b.
* @return the new value
**/
public boolean xor(boolean b) {
synchronized (lock_) {
value_ = value_ ^ b;
return value_;
}
}
public int compareTo(boolean other) {
boolean val = get();
return (val == other)? 0 : (val)? 1 : -1;
}
public int compareTo(SynchronizedBoolean other) {
return compareTo(other.get());
}
public int compareTo(Object other) {
return compareTo((SynchronizedBoolean)other);
}
public boolean equals(Object other) {
if (other != null &&
other instanceof SynchronizedBoolean)
return get() == ((SynchronizedBoolean)other).get();
else
return false;
}
public int hashCode() {
boolean b = get();
return (b)? 3412688 : 8319343; // entirely arbitrary
}
public String toString() { return String.valueOf(get()); }
}
concurrent-dfsg-1.3.4/FIFOReadWriteLock.java 0000644 0001750 0001750 00000013125 10202157355 021054 0 ustar wbaer wbaer 0000000 0000000 /*
File: FIFOReadWriteLock.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
23nov2001 dl Replace main algorithm with fairer
version based on one by Alexander Terekhov
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* This class implements a policy for reader/writer locks in which
* threads contend in a First-in/First-out manner for access (modulo
* the limitations of FIFOSemaphore, which is used for queuing). This
* policy does not particularly favor readers or writers. As a
* byproduct of the FIFO policy, the attempt methods may
* return false even when the lock might logically be
* available, but, due to contention, cannot be accessed within the
* given time bound.
*
* This lock is NOT reentrant. Current readers and
* writers should not try to re-obtain locks while holding them.
*
*
* [ Introduction to this package. ]
*
* @see FIFOSemaphore
**/
public class FIFOReadWriteLock implements ReadWriteLock {
/**
* Fair Semaphore serving as a kind of mutual exclusion lock.
* Writers acquire on entry, and hold until rwlock exit.
* Readers acquire and release only during entry (but are
* blocked from doing so if there is an active writer).
**/
protected final FIFOSemaphore entryLock = new FIFOSemaphore(1);
/**
* Number of threads that have entered read lock. Note that this is
* never reset to zero. Incremented only during acquisition of read
* lock while the "entryLock" is held, but read elsewhere, so is
* declared volatile.
**/
protected volatile int readers;
/**
* Number of threads that have exited read lock. Note that this is
* never reset to zero. Accessed only in code protected by
* synchronized(this). When exreaders != readers, the rwlock is
* being used for reading. Else if the entry lock is held, it is
* being used for writing (or in transition). Else it is free.
* Note: To distinguish these states, we assume that fewer than 2^32
* reader threads can simultaneously execute.
**/
protected int exreaders;
protected void acquireRead() throws InterruptedException {
entryLock.acquire();
++readers;
entryLock.release();
}
protected synchronized void releaseRead() {
/*
If this is the last reader, notify a possibly waiting writer.
Because waits occur only when entry lock is held, at most one
writer can be waiting for this notification. Because increments
to "readers" aren't protected by "this" lock, the notification
may be spurious (when an incoming reader in in the process of
updating the field), but at the point tested in acquiring write
lock, both locks will be held, thus avoiding false alarms. And
we will never miss an opportunity to send a notification when it
is actually needed.
*/
if (++exreaders == readers)
notify();
}
protected void acquireWrite() throws InterruptedException {
// Acquiring entryLock first forces subsequent entering readers
// (as well as writers) to block.
entryLock.acquire();
// Only read "readers" once now before loop. We know it won't
// change because we hold the entry lock needed to update it.
int r = readers;
try {
synchronized(this) {
while (exreaders != r)
wait();
}
}
catch (InterruptedException ie) {
entryLock.release();
throw ie;
}
}
protected void releaseWrite() {
entryLock.release();
}
protected boolean attemptRead(long msecs) throws InterruptedException {
if (!entryLock.attempt(msecs))
return false;
++readers;
entryLock.release();
return true;
}
protected boolean attemptWrite(long msecs) throws InterruptedException {
long startTime = (msecs <= 0)? 0 : System.currentTimeMillis();
if (!entryLock.attempt(msecs))
return false;
int r = readers;
try {
synchronized(this) {
while (exreaders != r) {
long timeLeft = (msecs <= 0)? 0:
msecs - (System.currentTimeMillis() - startTime);
if (timeLeft <= 0) {
entryLock.release();
return false;
}
wait(timeLeft);
}
return true;
}
}
catch (InterruptedException ie) {
entryLock.release();
throw ie;
}
}
// support for ReadWriteLock interface
protected class ReaderSync implements Sync {
public void acquire() throws InterruptedException {
acquireRead();
}
public void release() {
releaseRead();
}
public boolean attempt(long msecs) throws InterruptedException {
return attemptRead(msecs);
}
}
protected class WriterSync implements Sync {
public void acquire() throws InterruptedException {
acquireWrite();
}
public void release() {
releaseWrite();
}
public boolean attempt(long msecs) throws InterruptedException {
return attemptWrite(msecs);
}
}
protected final Sync readerSync = new ReaderSync();
protected final Sync writerSync = new WriterSync();
public Sync writeLock() { return writerSync; }
public Sync readLock() { return readerSync; }
}
* A x B
*
* A11 | A12 B11 | B12 A11*B11 | A11*B12 A12*B21 | A12*B22
* |----+----| x |----+----| = |--------+--------| + |---------+-------|
* A21 | A22 B21 | B21 A21*B11 | A21*B21 A22*B21 | A22*B22
*
*/
static class Multiplier extends FJTask {
final float[][] A; // Matrix A
final int aRow; // first row of current quadrant of A
final int aCol; // first column of current quadrant of A
final float[][] B; // Similarly for B
final int bRow;
final int bCol;
final float[][] C; // Similarly for result matrix C
final int cRow;
final int cCol;
final int size; // number of elements in current quadrant
Multiplier(float[][] A, int aRow, int aCol,
float[][] B, int bRow, int bCol,
float[][] C, int cRow, int cCol,
int size) {
this.A = A; this.aRow = aRow; this.aCol = aCol;
this.B = B; this.bRow = bRow; this.bCol = bCol;
this.C = C; this.cRow = cRow; this.cCol = cCol;
this.size = size;
}
public void run() {
if (size <= granularity) {
multiplyStride2();
}
else {
int h = size / 2;
coInvoke(new FJTask[] {
seq(new Multiplier(A, aRow, aCol, // A11
B, bRow, bCol, // B11
C, cRow, cCol, // C11
h),
new Multiplier(A, aRow, aCol+h, // A12
B, bRow+h, bCol, // B21
C, cRow, cCol, // C11
h)),
seq(new Multiplier(A, aRow, aCol, // A11
B, bRow, bCol+h, // B12
C, cRow, cCol+h, // C12
h),
new Multiplier(A, aRow, aCol+h, // A12
B, bRow+h, bCol+h, // B22
C, cRow, cCol+h, // C12
h)),
seq(new Multiplier(A, aRow+h, aCol, // A21
B, bRow, bCol, // B11
C, cRow+h, cCol, // C21
h),
new Multiplier(A, aRow+h, aCol+h, // A22
B, bRow+h, bCol, // B21
C, cRow+h, cCol, // C21
h)),
seq(new Multiplier(A, aRow+h, aCol, // A21
B, bRow, bCol+h, // B12
C, cRow+h, cCol+h, // C22
h),
new Multiplier(A, aRow+h, aCol+h, // A22
B, bRow+h, bCol+h, // B22
C, cRow+h, cCol+h, // C22
h))
});
}
}
/**
* Version of matrix multiplication that steps 2 rows and columns
* at a time. Adapted from Cilk demos.
* Note that the results are added into C, not just set into C.
* This works well here because Java array elements
* are created with all zero values.
**/
void multiplyStride2() {
for (int j = 0; j < size; j+=2) {
for (int i = 0; i < size; i +=2) {
float[] a0 = A[aRow+i];
float[] a1 = A[aRow+i+1];
float s00 = 0.0F;
float s01 = 0.0F;
float s10 = 0.0F;
float s11 = 0.0F;
for (int k = 0; k < size; k+=2) {
float[] b0 = B[bRow+k];
s00 += a0[aCol+k] * b0[bCol+j];
s10 += a1[aCol+k] * b0[bCol+j];
s01 += a0[aCol+k] * b0[bCol+j+1];
s11 += a1[aCol+k] * b0[bCol+j+1];
float[] b1 = B[bRow+k+1];
s00 += a0[aCol+k+1] * b1[bCol+j];
s10 += a1[aCol+k+1] * b1[bCol+j];
s01 += a0[aCol+k+1] * b1[bCol+j+1];
s11 += a1[aCol+k+1] * b1[bCol+j+1];
}
C[cRow+i] [cCol+j] += s00;
C[cRow+i] [cCol+j+1] += s01;
C[cRow+i+1][cCol+j] += s10;
C[cRow+i+1][cCol+j+1] += s11;
}
}
}
}
}
concurrent-dfsg-1.3.4/taskDemo/Integrate.java 0000644 0001750 0001750 00000010751 10202157355 021404 0 ustar wbaer wbaer 0000000 0000000 import EDU.oswego.cs.dl.util.concurrent.*;
/**
* Sample program using Guassian Quadrature for numerical integration.
* Inspired by a
* Filaments
* demo program.
*
*/
public class Integrate {
public static void main(String[] args) {
int procs;
double start;
double end;
int exp = 5;
try {
procs = Integer.parseInt(args[0]);
start = new Double(args[1]).doubleValue();
end = new Double(args[2]).doubleValue();
if (args.length > 3) exp = Integer.parseInt(args[3]);
}
catch (Exception e) {
System.out.println("Usage: java Integrate
* Computes fibonacci(n) = fibonacci(n-1) + fibonacci(n-2); for n> 1
* fibonacci(0) = 0;
* fibonacci(1) = 1.
*
**/
public class SFib extends FJTask {
// Performance-tuning constant:
static int sequentialThreshold = 0;
public static void main(String[] args) {
try {
int procs;
// int num;
try {
procs = Integer.parseInt(args[0]);
// num = Integer.parseInt(args[1]);
if (args.length > 2) sequentialThreshold = Integer.parseInt(args[2]);
}
catch (Exception e) {
System.out.println("Usage: java SFib Task framework demo programs
The programs in this directory include ones that I've used to test
and experiment with the task framework. You may also find
them useful as demonstrations of various constructions and
techniques that can be used with Tasks. However, most of
these programs are not themselves particularly useful, and
have not been constructed or documented with any concern for reuse
or extensibility. They are not properly packaged (i.e., they
do not declare to be in any package). They can be compiled
via: javac *.java
java Prog #threads [any other arguments]
where #threads
is the number of threads to establish in
a TaskGroupRunner that runs the tasks. All of the programs print out
ThreadGroup.stats(), normally at the ends of their runs. Some of
the programs do not bother printing out any further results. Some
programs, at some parameter settings deal with huge arrays and
matrices that require a lot of memory, so you might need to use
-Xmx
switches; for example -Xmx64m
to use
a maximum of 64Mbytes of memory.
Contents
java Fib 2 35
computes the 35th
fibonacci number with two threads. The optional sequential
threshold value controls the argument size under which it
uses a sequential version of fib (default is 0, meaning it
never does). See also FibVCB, a
callback-based version with same usage parameters.
(2*i-1)*power(x,
(2*i-1))
) for odd values of i up through e) is
pre-loaded. Call with lower and upper bounds. The e
value is a parameter of the function. Higher values cause the
function to both be slower to compute and take more iterations
(subdivisions) for its integral to converge. If not given, it
defaults to 5. For example, one reasonable set of test parameters
is: java Integrate 4 1 48 5
.
Doug Lea
Last modified: Tue Jan 18 07:12:03 EST 2000
concurrent-dfsg-1.3.4/taskDemo/FibVCB.java 0000644 0001750 0001750 00000004452 10202157355 020516 0 ustar wbaer wbaer 0000000 0000000 import EDU.oswego.cs.dl.util.concurrent.*;
/**
* Callback version of Fibonacci. Computes:
*
* Computes fibonacci(n) = fibonacci(n-1) + fibonacci(n-2); for n> 1
* fibonacci(0) = 0;
* fibonacci(1) = 1.
*
**/
public class FibVCB extends FJTask {
// Performance-tuning constant:
static int sequentialThreshold = 1;
public static void main(String[] args) {
try {
int procs;
int num;
try {
procs = Integer.parseInt(args[0]);
num = Integer.parseInt(args[1]);
if (args.length > 2) sequentialThreshold = Integer.parseInt(args[2]);
}
catch (Exception e) {
System.out.println("Usage: java FibVCB
* Computes fibonacci(n) = fibonacci(n-1) + fibonacci(n-2); for n> 1
* fibonacci(0) = 0;
* fibonacci(1) = 1.
*
**/
public class Fib extends FJTask {
// Performance-tuning constant:
static int sequentialThreshold = 0;
public static void main(String[] args) {
try {
int procs;
int num;
try {
procs = Integer.parseInt(args[0]);
num = Integer.parseInt(args[1]);
if (args.length > 2) sequentialThreshold = Integer.parseInt(args[2]);
}
catch (Exception e) {
System.out.println("Usage: java Fib Long.MAX_VALUE
will not impose a
* timeout but will create an additional thread of control that will respond
* to an interrupt even if the construct
implementation ignores
* them.
*
* import EDU.oswego.cs.dl.util.concurrent.TimeoutException;
* import EDU.oswego.cs.dl.util.concurrent.misc.SwingWorker;
*
* public class SwingWorkerDemo extends javax.swing.JApplet {
*
* private static final int TIMEOUT = 5000; // 5 seconds
* private javax.swing.JLabel status;
* private javax.swing.JButton start;
* private SwingWorker worker;
*
* public SwingWorkerDemo() {
* status = new javax.swing.JLabel("Ready");
* status.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
* getContentPane().add(status, java.awt.BorderLayout.CENTER);
* start = new javax.swing.JButton("Start");
* getContentPane().add(start, java.awt.BorderLayout.SOUTH);
*
* start.addActionListener(new java.awt.event.ActionListener() {
* public void actionPerformed(java.awt.event.ActionEvent evt) {
* if (start.getText().equals("Start")) {
* start.setText("Stop");
* status.setText("Working...");
* worker = new DemoSwingWorker(TIMEOUT);
* worker.start();
* } else {
* worker.interrupt();
* }
* }
* });
* }
*
* private class DemoSwingWorker extends SwingWorker {
* private static final java.util.Random RAND = new java.util.Random();
* public DemoSwingWorker(long msecs) {
* super(msecs);
* }
* protected Object construct() throws InterruptedException {
* // Take a random nap. If we oversleep, the worker times out.
* Thread.sleep(RAND.nextInt(2*TIMEOUT));
* return "Success";
* }
* protected void finished() {
* start.setText("Start");
* try {
* Object result = get();
* status.setText((String) result);
* }
* catch (java.lang.reflect.InvocationTargetException e) {
* Throwable ex = e.getTargetException();
* if (ex instanceof TimeoutException) {
* status.setText("Timed out.");
* } else if (ex instanceof InterruptedException) {
* status.setText("Interrupted.");
* } else {
* status.setText("Exception: " + ex);
* }
* }
* catch (InterruptedException ex) {
* // event-dispatch thread won't be interrupted
* throw new IllegalStateException(ex+"");
* }
* }
* }
* }
*
*
* @author Joseph Bowbeer
* @author Hans Muller
* @version 3.0
*
* get
method. */
private final FutureResult result = new FutureResult();
/** Maximum time to wait for worker to complete. */
private final long timeout;
/** Worker thread. */
private Thread thread;
/** Creates new SwingWorker with no timeout. */
public SwingWorker() {
this(FACTORY, 0);
}
/**
* Creates new SwingWorker with specified timeout.
* @param msecs timeout in milliseconds, or 0
* for no time limit.
*/
public SwingWorker(long msecs) {
this(FACTORY, msecs);
}
/**
* Creates new SwingWorker with specified thread factory and timeout.
* @param factory factory for worker threads.
* @param msecs timeout in milliseconds, or 0
* for no time limit.
*/
protected SwingWorker(ThreadFactory factory, long msecs) {
setThreadFactory(factory);
if (msecs < 0) {
throw new IllegalArgumentException("timeout="+msecs);
}
timeout = msecs;
}
/**
* Computes the value to be returned by the get
method.
*/
protected abstract Object construct() throws Exception;
/**
* Called on the event dispatching thread (not on the worker thread)
* after the construct
method has returned.
*/
protected void finished() { }
/**
* Returns timeout period in milliseconds. Timeout is the
* maximum time to wait for worker to complete. There is
* no time limit if timeout is 0
(default).
*/
public long getTimeout() {
return timeout;
}
/**
* Calls the construct
method to compute the result,
* and then invokes the finished
method on the event
* dispatch thread.
*/
public void run() {
Callable function = new Callable() {
public Object call() throws Exception {
return construct();
}
};
Runnable doFinished = new Runnable() {
public void run() {
finished();
}
};
/* Convert to TimedCallable if timeout is specified. */
long msecs = getTimeout();
if (msecs != 0) {
TimedCallable tc = new TimedCallable(function, msecs);
tc.setThreadFactory(getThreadFactory());
function = tc;
}
result.setter(function).run();
SwingUtilities.invokeLater(doFinished);
}
/**
* Starts the worker thread.
*/
public synchronized void start() {
if (thread == null) {
thread = getThreadFactory().newThread(this);
}
thread.start();
}
/**
* Stops the worker and sets the exception to InterruptedException.
*/
public synchronized void interrupt() {
if (thread != null) {
/* Try-catch is workaround for JDK1.2 applet security bug.
On some platforms, a security exception is thrown if an
applet interrupts a thread that is no longer alive. */
try { thread.interrupt(); } catch (Exception ex) { }
}
result.setException(new InterruptedException());
}
/**
* Return the value created by the construct
method,
* waiting if necessary until it is ready.
*
* @return the value created by the construct
method
* @exception InterruptedException if current thread was interrupted
* @exception InvocationTargetException if the constructing thread
* encountered an exception or was interrupted.
*/
public Object get()
throws InterruptedException, InvocationTargetException {
return result.get();
}
/**
* Wait at most msecs to access the constructed result.
* @return current value
* @exception TimeoutException if not ready after msecs
* @exception InterruptedException if current thread has been interrupted
* @exception InvocationTargetException if the constructing thread
* encountered an exception or was interrupted.
*/
public Object timedGet(long msecs)
throws TimeoutException, InterruptedException, InvocationTargetException {
return result.timedGet(msecs);
}
/**
* Get the exception, or null if there isn't one (yet).
* This does not wait until the worker is ready, so should
* ordinarily only be called if you know it is.
* @return the exception encountered by the construct
* method wrapped in an InvocationTargetException
*/
public InvocationTargetException getException() {
return result.getException();
}
/**
* Return whether the get
method is ready to
* return a value.
*
* @return true if a value or exception has been set. else false
*/
public boolean isReady() {
return result.isReady();
}
}
concurrent-dfsg-1.3.4/misc/FIFOSlot.java 0000644 0001750 0001750 00000001610 10202157355 020225 0 ustar wbaer wbaer 0000000 0000000 package EDU.oswego.cs.dl.util.concurrent.misc;
import EDU.oswego.cs.dl.util.concurrent.*;
// demo showing one way to make special channels
public class FIFOSlot implements BoundedChannel {
private final Slot slot_;
public FIFOSlot() {
try {
slot_ = new Slot(FIFOSemaphore.class);
}
catch (Exception ex) {
ex.printStackTrace();
throw new Error("Cannot make Slot?");
}
}
public void put(Object item) throws InterruptedException {
slot_.put(item);
}
public boolean offer(Object item, long msecs) throws InterruptedException {
return slot_.offer(item, msecs);
}
public Object take() throws InterruptedException {
return slot_.take();
}
public Object poll(long msecs) throws InterruptedException {
return slot_.poll(msecs);
}
public int capacity() { return 1; }
public Object peek() {
return slot_.peek();
}
}
concurrent-dfsg-1.3.4/misc/CVBuffer.java 0000644 0001750 0001750 00000004751 10202157355 020313 0 ustar wbaer wbaer 0000000 0000000
package EDU.oswego.cs.dl.util.concurrent.misc;
import EDU.oswego.cs.dl.util.concurrent.*;
public class CVBuffer implements BoundedChannel {
private final Mutex mutex;
private final CondVar notFull;
private final CondVar notEmpty;
private int count = 0;
private int takePtr = 0;
private int putPtr = 0;
private final Object[] array;
public CVBuffer(int cap) {
array = new Object[cap];
mutex = new Mutex();
notFull = new CondVar(mutex);
notEmpty = new CondVar(mutex);
}
public CVBuffer() {
this(DefaultChannelCapacity.get());
}
public int capacity() { return array.length; }
public void put(Object x) throws InterruptedException {
mutex.acquire();
try {
while (count == array.length) {
notFull.await();
}
array[putPtr] = x;
putPtr = (putPtr + 1) % array.length;
++count;
notEmpty.signal();
}
finally {
mutex.release();
}
}
public Object take() throws InterruptedException {
Object x = null;
mutex.acquire();
try {
while (count == 0) {
notEmpty.await();
}
x = array[takePtr];
array[takePtr] = null;
takePtr = (takePtr + 1) % array.length;
--count;
notFull.signal();
}
finally {
mutex.release();
}
return x;
}
public boolean offer(Object x, long msecs) throws InterruptedException {
mutex.acquire();
try {
if (count == array.length) {
notFull.timedwait(msecs);
if (count == array.length)
return false;
}
array[putPtr] = x;
putPtr = (putPtr + 1) % array.length;
++count;
notEmpty.signal();
return true;
}
finally {
mutex.release();
}
}
public Object poll(long msecs) throws InterruptedException {
Object x = null;
mutex.acquire();
try {
if (count == 0) {
notEmpty.timedwait(msecs);
if (count == 0)
return null;
}
x = array[takePtr];
array[takePtr] = null;
takePtr = (takePtr + 1) % array.length;
--count;
notFull.signal();
}
finally {
mutex.release();
}
return x;
}
public Object peek() {
try {
mutex.acquire();
try {
if (count == 0)
return null;
else
return array[takePtr];
}
finally {
mutex.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
return null;
}
}
}
concurrent-dfsg-1.3.4/misc/Fraction.java 0000644 0001750 0001750 00000013203 10202157355 020406 0 ustar wbaer wbaer 0000000 0000000 /*
File: Fraction.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
7Jul1998 dl Create public version
11Oct1999 dl add hashCode
*/
package EDU.oswego.cs.dl.util.concurrent.misc;
/**
* An immutable class representing fractions as pairs of longs.
* Fractions are always maintained in reduced form.
**/
public class Fraction implements Cloneable, Comparable, java.io.Serializable {
protected final long numerator_;
protected final long denominator_;
/** Return the numerator **/
public final long numerator() { return numerator_; }
/** Return the denominator **/
public final long denominator() { return denominator_; }
/** Create a Fraction equal in value to num / den **/
public Fraction(long num, long den) {
// normalize while constructing
boolean numNonnegative = (num >= 0);
boolean denNonnegative = (den >= 0);
long a = numNonnegative? num : -num;
long b = denNonnegative? den : -den;
long g = gcd(a, b);
numerator_ = (numNonnegative == denNonnegative)? (a / g) : (-a / g);
denominator_ = b / g;
}
/** Create a fraction with the same value as Fraction f **/
public Fraction(Fraction f) {
numerator_ = f.numerator();
denominator_ = f.denominator();
}
public String toString() {
if (denominator() == 1)
return "" + numerator();
else
return numerator() + "/" + denominator();
}
public Object clone() { return new Fraction(this); }
/** Return the value of the Fraction as a double **/
public double asDouble() {
return ((double)(numerator())) / ((double)(denominator()));
}
/**
* Compute the nonnegative greatest common divisor of a and b.
* (This is needed for normalizing Fractions, but can be
* useful on its own.)
**/
public static long gcd(long a, long b) {
long x;
long y;
if (a < 0) a = -a;
if (b < 0) b = -b;
if (a >= b) { x = a; y = b; }
else { x = b; y = a; }
while (y != 0) {
long t = x % y;
x = y;
y = t;
}
return x;
}
/** return a Fraction representing the negated value of this Fraction **/
public Fraction negative() {
long an = numerator();
long ad = denominator();
return new Fraction(-an, ad);
}
/** return a Fraction representing 1 / this Fraction **/
public Fraction inverse() {
long an = numerator();
long ad = denominator();
return new Fraction(ad, an);
}
/** return a Fraction representing this Fraction plus b **/
public Fraction plus(Fraction b) {
long an = numerator();
long ad = denominator();
long bn = b.numerator();
long bd = b.denominator();
return new Fraction(an*bd+bn*ad, ad*bd);
}
/** return a Fraction representing this Fraction plus n **/
public Fraction plus(long n) {
long an = numerator();
long ad = denominator();
long bn = n;
long bd = 1;
return new Fraction(an*bd+bn*ad, ad*bd);
}
/** return a Fraction representing this Fraction minus b **/
public Fraction minus(Fraction b) {
long an = numerator();
long ad = denominator();
long bn = b.numerator();
long bd = b.denominator();
return new Fraction(an*bd-bn*ad, ad*bd);
}
/** return a Fraction representing this Fraction minus n **/
public Fraction minus(long n) {
long an = numerator();
long ad = denominator();
long bn = n;
long bd = 1;
return new Fraction(an*bd-bn*ad, ad*bd);
}
/** return a Fraction representing this Fraction times b **/
public Fraction times(Fraction b) {
long an = numerator();
long ad = denominator();
long bn = b.numerator();
long bd = b.denominator();
return new Fraction(an*bn, ad*bd);
}
/** return a Fraction representing this Fraction times n **/
public Fraction times(long n) {
long an = numerator();
long ad = denominator();
long bn = n;
long bd = 1;
return new Fraction(an*bn, ad*bd);
}
/** return a Fraction representing this Fraction divided by b **/
public Fraction dividedBy(Fraction b) {
long an = numerator();
long ad = denominator();
long bn = b.numerator();
long bd = b.denominator();
return new Fraction(an*bd, ad*bn);
}
/** return a Fraction representing this Fraction divided by n **/
public Fraction dividedBy(long n) {
long an = numerator();
long ad = denominator();
long bn = n;
long bd = 1;
return new Fraction(an*bd, ad*bn);
}
/** return a number less, equal, or greater than zero
* reflecting whether this Fraction is less, equal or greater than
* the value of Fraction other.
**/
public int compareTo(Object other) {
Fraction b = (Fraction)(other);
long an = numerator();
long ad = denominator();
long bn = b.numerator();
long bd = b.denominator();
long l = an*bd;
long r = bn*ad;
return (l < r)? -1 : ((l == r)? 0: 1);
}
/** return a number less, equal, or greater than zero
* reflecting whether this Fraction is less, equal or greater than n.
**/
public int compareTo(long n) {
long an = numerator();
long ad = denominator();
long bn = n;
long bd = 1;
long l = an*bd;
long r = bn*ad;
return (l < r)? -1 : ((l == r)? 0: 1);
}
public boolean equals(Object other) {
return compareTo((Fraction)other) == 0;
}
public boolean equals(long n) {
return compareTo(n) == 0;
}
public int hashCode() {
return (int) (numerator_ ^ denominator_);
}
}
concurrent-dfsg-1.3.4/misc/PipedChannel.java 0000644 0001750 0001750 00000006025 10202157355 021177 0 ustar wbaer wbaer 0000000 0000000
package EDU.oswego.cs.dl.util.concurrent.misc;
import EDU.oswego.cs.dl.util.concurrent.*;
import java.io.*;
/**
* A channel based on a java.io.PipedInputStream and
* java.io.PipedOutputStream. Elements are serialized
* using ObjectInputStreams and ObjectOutputStreams
* upon insertion and extraction from the pipe.
*
*
*
*
* You'll need Swing (JFC). (This
* program currently imports the javax.swing versions.
* You can edit imports to instead use other versions.)
*
* RNG
, which is just a hacked random
* number generator class. Objects of this class have just enough
* state and require just enough computation to be reasonable minimal
* targets. (Additionally, random numbers are needed a lot in these
* kinds of time tests, so basing them on objects that produce random
* numbers is convenient.) Computation of each random number is
* padded a bit with an adjustable compute loop running a random
* number of times to avoid getting schedulers locked into
* uninteresting patterns.
*
* perfmeter
or top
on unix)
* alongside this program
* to find out.
*
*
*
*
*
*
*
*
*
* Sync
classes as locks
* Mutex
,
* but, for example, a Semaphore initialized to 1 also works.
* On the other hand, many other Sync implementations would not
* work here, so some care is required to supply a sensible
* synchronization object.
**/
public LockedExecutor(Sync mutex) {
mutex_ = mutex;
}
/**
* Execute the given command directly in the current thread,
* within the supplied lock.
**/
public void execute(Runnable command) throws InterruptedException {
mutex_.acquire();
try {
command.run();
}
finally {
mutex_.release();
}
}
}
concurrent-dfsg-1.3.4/CyclicBarrier.java 0000644 0001750 0001750 00000022552 10202157355 020432 0 ustar wbaer wbaer 0000000 0000000 /*
File: CyclicBarrier.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jul1998 dl Create public version
28Aug1998 dl minor code simplification
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A cyclic barrier is a reasonable choice for a barrier in contexts
* involving a fixed sized group of threads that
* must occasionally wait for each other.
* (A Rendezvous better handles applications in which
* any number of threads meet, n-at-a-time.)
* restart
ed. This is usually
* the simplest and best strategy for sharing knowledge
* about failures among cooperating threads in the most
* common usages contexts of Barriers.
* This implementation has the property that interruptions
* among newly arriving threads can cause as-yet-unresumed
* threads from a previous barrier cycle to return out
* as broken. This transmits breakage
* as early as possible, but with the possible byproduct that
* only some threads returning out of a barrier will realize
* that it is newly broken. (Others will not realize this until a
* future cycle.) (The Rendezvous class has a more uniform, but
* sometimes less desirable policy.)
*
* 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.barrier();
* }
* catch (InterruptedException ex) { return; }
* catch (BrokenBarrierException ex) { return; }
* }
* }
* }
*
* public Solver(float[][] matrix) {
* data = matrix;
* N = matrix.length;
* barrier = new CyclicBarrier(N);
* barrier.setBarrierCommand(new Runnable() {
* public void run() { mergeRows(...); }
* });
* for (int i = 0; i < N; ++i) {
* new Thread(new Worker(i)).start();
* waitUntilDone();
* }
* }
*
* restart
* operation left the barrier
* prematurely due to interruption or time-out. (If so,
* the broken
status is also set.)
* Threads that are notified to have been
* interrupted after being released are not considered
* to have broken the barrier.
* In all cases, the interruption
* status of the current thread is preserved, so can be tested
* by checking Thread.interrupted
.
* @exception InterruptedException if this thread was interrupted
* during the barrier, and was the one causing breakage.
* If so, broken
status is also set.
**/
public int barrier() throws InterruptedException, BrokenBarrierException {
return doBarrier(false, 0);
}
/**
* Enter barrier and wait at most msecs for the other parties()-1 threads.
* @return if not timed out, the arrival index: the number of other parties
* that were still waiting
* upon entry. This is a unique value from zero to parties()-1.
* If it is zero, then the current
* thread was the last party to hit barrier point
* and so was responsible for releasing the others.
* @exception BrokenBarrierException
* if any other thread
* in any previous or current barrier
* since either creation or the last restart
* operation left the barrier
* prematurely due to interruption or time-out. (If so,
* the broken
status is also set.)
* Threads that are noticed to have been
* interrupted after being released are not considered
* to have broken the barrier.
* In all cases, the interruption
* status of the current thread is preserved, so can be tested
* by checking Thread.interrupted
.
* @exception InterruptedException if this thread was interrupted
* during the barrier. If so, broken
status is also set.
* @exception TimeoutException if this thread timed out waiting for
* the barrier. If the timeout occured while already in the
* barrier, broken
status is also set.
**/
public int attemptBarrier(long msecs)
throws InterruptedException, TimeoutException, BrokenBarrierException {
return doBarrier(true, msecs);
}
protected synchronized int doBarrier(boolean timed, long msecs)
throws InterruptedException, TimeoutException, BrokenBarrierException {
int index = --count_;
if (broken_) {
throw new BrokenBarrierException(index);
}
else if (Thread.interrupted()) {
broken_ = true;
notifyAll();
throw new InterruptedException();
}
else if (index == 0) { // tripped
count_ = parties_;
++resets_;
notifyAll();
try {
if (barrierCommand_ != null)
barrierCommand_.run();
return 0;
}
catch (RuntimeException ex) {
broken_ = true;
return 0;
}
}
else if (timed && msecs <= 0) {
broken_ = true;
notifyAll();
throw new TimeoutException(msecs);
}
else { // wait until next reset
int r = resets_;
long startTime = (timed)? System.currentTimeMillis() : 0;
long waitTime = msecs;
for (;;) {
try {
wait(waitTime);
}
catch (InterruptedException ex) {
// Only claim that broken if interrupted before reset
if (resets_ == r) {
broken_ = true;
notifyAll();
throw ex;
}
else {
Thread.currentThread().interrupt(); // propagate
}
}
if (broken_)
throw new BrokenBarrierException(index);
else if (r != resets_)
return index;
else if (timed) {
waitTime = msecs - (System.currentTimeMillis() - startTime);
if (waitTime <= 0) {
broken_ = true;
notifyAll();
throw new TimeoutException(msecs);
}
}
}
}
}
}
concurrent-dfsg-1.3.4/WaiterPreferenceSemaphore.java 0000644 0001750 0001750 00000010453 10202157355 023010 0 ustar wbaer wbaer 0000000 0000000 /*
File: WaiterPreferenceSemaphore.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
5Aug1998 dl replaced int counters with longs
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* An implementation of counting Semaphores that
* enforces enough fairness for applications that
* need to avoid indefinite overtaking without
* necessarily requiring FIFO ordered access.
* Empirically, very little is paid for this property
* unless there is a lot of contention among threads
* or very unfair JVM scheduling.
* The acquire method waits even if there are permits
* available but have not yet been claimed by threads that have
* been notified but not yet resumed. This makes the semaphore
* almost as fair as the underlying Java primitives allow.
* So, if synch lock entry and notify are both fair
* so is the semaphore -- almost: Rewaits stemming
* from timeouts in attempt, along with potentials for
* interrupted threads to be notified can compromise fairness,
* possibly allowing later-arriving threads to pass before
* later arriving ones. However, in no case can a newly
* entering thread obtain a permit if there are still others waiting.
* Also, signalling order need not coincide with
* resumption order. Later-arriving threads might get permits
* and continue before other resumable threads are actually resumed.
* However, all of these potential fairness breaches are
* very rare in practice unless the underlying JVM
* performs strictly LIFO notifications (which has, sadly enough,
* been known to occur) in which case you need to use
* a FIFOSemaphore to maintain a reasonable approximation
* of fairness.
*
* Mutex lock = new Mutex();
* TimeoutSync timedLock = new TimeoutSync(lock, 1000); // 1 sec timeouts
* Set set = new SyncSet(new HashSet(), timedlock);
* try {
* set. add("hi");
* }
* // SyncSets translate timeouts and other lock failures
* // to unsupported operation exceptions,
* catch (UnsupportedOperationException ex) {
* System.out.println("Lock failure");
* }
*
*
*
* class Worker implements Runnable {
* private final CountDown done;
* Worker(CountDown d) { done = d; }
* public void run() {
* doWork();
* done.release();
* }
* }
*
* class Driver { // ...
* void main() {
* CountDown done = new CountDown(N);
* for (int i = 0; i < N; ++i)
* new Thread(new Worker(done)).start();
* doSomethingElse();
* done.acquire(); // wait for all to finish
* }
* }
*
*
* put
and poll
methods are useful in most
* applications. Because the queue does not support blocking
* operations, take
relies on spin-loops, which can be
* extremely wasteful. at
* (and the associated crond) in Unix.
* Objects of this class maintain a single thread and a task queue
* that may be used to execute Runnable commands in any of three modes --
* absolute (run at a given time), relative (run after a given delay),
* and periodic (cyclically run with a given delay).
* restart()
is invoked.
* setDaemon
status.
*
* class X { ...
*
* ClockDaemon timer = ...
* Thread readerThread;
* FileInputStream datafile;
*
* void startReadThread() {
* datafile = new FileInputStream("data", ...);
*
* readerThread = new Thread(new Runnable() {
* public void run() {
* for(;;) {
* // try to gracefully exit before blocking
* if (Thread.currentThread().isInterrupted()) {
* quietlyWrapUpAndReturn();
* }
* else {
* try {
* int c = datafile.read();
* if (c == -1) break;
* else process(c);
* }
* catch (IOException ex) {
* cleanup();
* return;
* }
* }
* } };
*
* readerThread.start();
*
* // establish callback to cancel after 60 seconds
* timer.executeAfterDelay(60000, new Runnable() {
* readerThread.interrupt(); // try to interrupt thread
* datafile.close(); // force thread to lose its input file
* });
* }
* }
*
* @param millisecondsToDelay -- the number of milliseconds
* from now to run the command.
* @param command -- the command to run after the delay.
* @return taskID -- an opaque reference that can be used to cancel execution request
**/
public Object executeAfterDelay(long millisecondsToDelay, Runnable command) {
long runtime = System.currentTimeMillis() + millisecondsToDelay;
TaskNode task = new TaskNode(runtime, command);
heap_.insert(task);
restart();
return task;
}
/**
* Execute the given command every period
milliseconds.
* If startNow
is true, execution begins immediately,
* otherwise, it begins after the first period
delay.
*
* class X {
* JLabel statusLabel = ...;
*
* int percentComplete = 0;
* synchronized int getPercentComplete() { return percentComplete; }
* synchronized void setPercentComplete(int p) { percentComplete = p; }
*
* ClockDaemon cd = ...;
*
* void startWorking() {
* Runnable showPct = new Runnable() {
* public void run() {
* SwingUtilities.invokeLater(new Runnable() {
* public void run() {
* statusLabel.setText(getPercentComplete() + "%");
* }
* }
* }
* };
*
* final Object updater = cd.executePeriodically(500, showPct, true);
*
* Runnable action = new Runnable() {
* public void run() {
* for (int i = 0; i < 100; ++i) {
* work();
* setPercentComplete(i);
* }
* cd.cancel(updater);
* }
* };
*
* new Thread(action).start();
* }
* }
*
* @param period -- the period, in milliseconds. Periods are
* measured from start-of-task to the next start-of-task. It is
* generally a bad idea to use a period that is shorter than
* the expected task duration.
* @param command -- the command to run at each cycle
* @param startNow -- true if the cycle should start with execution
* of the task now. Otherwise, the cycle starts with a delay of
* period
milliseconds.
* @exception IllegalArgumentException if period less than or equal to zero.
* @return taskID -- an opaque reference that can be used to cancel execution request
**/
public Object executePeriodically(long period,
Runnable command,
boolean startNow) {
if (period <= 0) throw new IllegalArgumentException();
long firstTime = System.currentTimeMillis();
if (!startNow) firstTime += period;
TaskNode task = new TaskNode(firstTime, command, period);
heap_.insert(task);
restart();
return task;
}
/**
* Cancel a scheduled task that has not yet been run.
* The task will be cancelled
* upon the next opportunity to run it. This has no effect if
* this is a one-shot task that has already executed.
* Also, if an execution is in progress, it will complete normally.
* (It may however be interrupted via getThread().interrupt()).
* But if it is a periodic task, future iterations are cancelled.
* @param taskID -- a task reference returned by one of
* the execute commands
* @exception ClassCastException if the taskID argument is not
* of the type returned by an execute command.
**/
public static void cancel(Object taskID) {
((TaskNode)taskID).setCancelled();
}
/** The thread used to process commands **/
protected Thread thread_;
/**
* Return the thread being used to process commands, or
* null if there is no such thread. You can use this
* to invoke any special methods on the thread, for
* example, to interrupt it.
**/
public synchronized Thread getThread() {
return thread_;
}
/** set thread_ to null to indicate termination **/
protected synchronized void clearThread() {
thread_ = null;
}
/**
* Start (or restart) a thread to process commands, or wake
* up an existing thread if one is already running. This
* method can be invoked if the background thread crashed
* due to an unrecoverable exception in an executed command.
**/
public synchronized void restart() {
if (thread_ == null) {
thread_ = threadFactory_.newThread(runLoop_);
thread_.start();
}
else
notify();
}
/**
* Cancel all tasks and interrupt the background thread executing
* the current task, if any.
* A new background thread will be started if new execution
* requests are encountered. If the currently executing task
* does not repsond to interrupts, the current thread may persist, even
* if a new thread is started via restart().
**/
public synchronized void shutDown() {
heap_.clear();
if (thread_ != null)
thread_.interrupt();
thread_ = null;
}
/** Return the next task to execute, or null if thread is interrupted **/
protected synchronized TaskNode nextTask() {
// Note: This code assumes that there is only one run loop thread
try {
while (!Thread.interrupted()) {
// Using peek simplifies dealing with spurious wakeups
TaskNode task = (TaskNode)(heap_.peek());
if (task == null) {
wait();
}
else {
long now = System.currentTimeMillis();
long when = task.getTimeToRun();
if (when > now) { // false alarm wakeup
wait(when - now);
}
else {
task = (TaskNode)(heap_.extract());
if (!task.getCancelled()) { // Skip if cancelled by
if (task.period > 0) { // If periodic, requeue
task.setTimeToRun(now + task.period);
heap_.insert(task);
}
return task;
}
}
}
}
}
catch (InterruptedException ex) { } // fall through
return null; // on interrupt
}
/**
* The runloop is isolated in its own Runnable class
* just so that the main
* class need not implement Runnable, which would
* allow others to directly invoke run, which is not supported.
**/
protected class RunLoop implements Runnable {
public void run() {
try {
for (;;) {
TaskNode task = nextTask();
if (task != null)
task.command.run();
else
break;
}
}
finally {
clearThread();
}
}
}
protected final RunLoop runLoop_;
/**
* Create a new ClockDaemon
**/
public ClockDaemon() {
runLoop_ = new RunLoop();
}
}
concurrent-dfsg-1.3.4/SemaphoreControlledChannel.java 0000644 0001750 0001750 00000011164 10202157355 023154 0 ustar wbaer wbaer 0000000 0000000 /*
File: SemaphoreControlledChannel.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
16Jun1998 dl Create public version
5Aug1998 dl replaced int counters with longs
08dec2001 dl reflective constructor now uses longs too.
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.lang.reflect.*;
/**
* Abstract class for channels that use Semaphores to
* control puts and takes.
* INITIAL_DEFAULT_CAPACITY
* @see #INITIAL_DEFAULT_CAPACITY
*/
public static int get() {
return defaultCapacity_.get();
}
}
concurrent-dfsg-1.3.4/SyncSortedSet.java 0000644 0001750 0001750 00000006301 10202157355 020460 0 ustar wbaer wbaer 0000000 0000000 /*
File: SyncSortedSet.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
1Aug1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.util.*;
/**
* SyncSortedSets wrap Sync-based control around java.util.SortedSets.
* They support the following additional reader operations over
* SyncCollection: comparator, subSet, headSet, tailSet, first, last.
*
*
* restart
ed. This is usually
* the simplest and best strategy for sharing knowledge
* about failures among cooperating threads in the most
* common usages contexts of Rendezvous.
*
* class FillAndEmpty {
* Rendezvous exchanger = new Rendezvous(2);
* Buffer initialEmptyBuffer = ... a made-up type
* Buffer initialFullBuffer = ...
*
* class FillingLoop implements Runnable {
* public void run() {
* Buffer currentBuffer = initialEmptyBuffer;
* try {
* while (currentBuffer != null) {
* addToBuffer(currentBuffer);
* if (currentBuffer.full())
* currentBuffer = (Buffer)(exchanger.rendezvous(currentBuffer));
* }
* }
* catch (BrokenBarrierException ex) {
* return;
* }
* catch (InterruptedException ex) {
* Thread.currentThread().interrupt();
* }
* }
* }
*
* class EmptyingLoop implements Runnable {
* public void run() {
* Buffer currentBuffer = initialFullBuffer;
* try {
* while (currentBuffer != null) {
* takeFromBuffer(currentBuffer);
* if (currentBuffer.empty())
* currentBuffer = (Buffer)(exchanger.rendezvous(currentBuffer));
* }
* }
* catch (BrokenBarrierException ex) {
* return;
* }
* catch (InterruptedException ex) {
* Thread.currentThread().interrupt();
* }
* }
* }
*
* void start() {
* new Thread(new FillingLoop()).start();
* new Thread(new EmptyingLoop()).start();
* }
* }
*
* restart
* operation left the barrier
* prematurely due to interruption or time-out. (If so,
* the broken
status is also set.)
* Also returns as
* broken if the RendezvousFunction encountered a run-time exception.
* Threads that are noticed to have been
* interrupted after being released are not considered
* to have broken the barrier.
* In all cases, the interruption
* status of the current thread is preserved, so can be tested
* by checking Thread.interrupted
.
* @exception InterruptedException if this thread was interrupted
* during the exchange. If so, broken
status is also set.
**/
public Object rendezvous(Object x) throws InterruptedException, BrokenBarrierException {
return doRendezvous(x, false, 0);
}
/**
* Wait msecs to complete a rendezvous.
* @param x the item to present at rendezvous point.
* By default, this item is exchanged with another.
* @param msecs The maximum time to wait.
* @return an item x given by some thread, and/or processed
* by the rendezvousFunction.
* @exception BrokenBarrierException
* if any other thread
* in any previous or current barrier
* since either creation or the last restart
* operation left the barrier
* prematurely due to interruption or time-out. (If so,
* the broken
status is also set.)
* Also returns as
* broken if the RendezvousFunction encountered a run-time exception.
* Threads that are noticed to have been
* interrupted after being released are not considered
* to have broken the barrier.
* In all cases, the interruption
* status of the current thread is preserved, so can be tested
* by checking Thread.interrupted
.
* @exception InterruptedException if this thread was interrupted
* during the exchange. If so, broken
status is also set.
* @exception TimeoutException if this thread timed out waiting for
* the exchange. If the timeout occured while already in the
* exchange, broken
status is also set.
**/
public Object attemptRendezvous(Object x, long msecs)
throws InterruptedException, TimeoutException, BrokenBarrierException {
return doRendezvous(x, true, msecs);
}
protected Object doRendezvous(Object x, boolean timed, long msecs)
throws InterruptedException, TimeoutException, BrokenBarrierException {
// rely on semaphore to throw interrupt on entry
long startTime;
if (timed) {
startTime = System.currentTimeMillis();
if (!entryGate_.attempt(msecs)) {
throw new TimeoutException(msecs);
}
}
else {
startTime = 0;
entryGate_.acquire();
}
synchronized(this) {
Object y = null;
int index = entries_++;
slots_[index] = x;
try {
// last one in runs function and releases
if (entries_ == parties_) {
departures_ = entries_;
notifyAll();
try {
if (!broken_ && rendezvousFunction_ != null)
rendezvousFunction_.rendezvousFunction(slots_);
}
catch (RuntimeException ex) {
broken_ = true;
}
}
else {
while (!broken_ && departures_ < 1) {
long timeLeft = 0;
if (timed) {
timeLeft = msecs - (System.currentTimeMillis() - startTime);
if (timeLeft <= 0) {
broken_ = true;
departures_ = entries_;
notifyAll();
throw new TimeoutException(msecs);
}
}
try {
wait(timeLeft);
}
catch (InterruptedException ex) {
if (broken_ || departures_ > 0) { // interrupted after release
Thread.currentThread().interrupt();
break;
}
else {
broken_ = true;
departures_ = entries_;
notifyAll();
throw ex;
}
}
}
}
}
finally {
y = slots_[index];
// Last one out cleans up and allows next set of threads in
if (--departures_ <= 0) {
for (int i = 0; i < slots_.length; ++i) slots_[i] = null;
entryGate_.release(entries_);
entries_ = 0;
}
}
// continue if no IE/TO throw
if (broken_)
throw new BrokenBarrierException(index);
else
return y;
}
}
}
concurrent-dfsg-1.3.4/Heap.java 0000644 0001750 0001750 00000007644 10202157355 016577 0 ustar wbaer wbaer 0000000 0000000 /*
File: Heap.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
29Aug1998 dl Refactored from BoundedPriorityQueue
08dec2001 dl Null out slots of removed items
03feb2002 dl Also null out in clear
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.util.Comparator;
/**
* A heap-based priority queue, without any concurrency control
* (i.e., no blocking on empty/full states).
* This class provides the data structure mechanics for BoundedPriorityQueue.
* execute
* (as performed in ThreadedExecutor)
* is new Thread(command).start();
.
* However, this interface allows implementations that instead
* employ queueing or pooling, or perform additional
* bookkeeping.
*
*
* Writer operations are:
*
*
*
*
* class X {
* Sync gate;
* // ...
*
* public void m() {
* try {
* gate.acquire(); // block until condition holds
* try {
* // ... method body
* }
* finally {
* gate.release()
* }
* }
* catch (InterruptedException ex) {
* // ... evasive action
* }
* }
*
* public void m2(Sync cond) { // use supplied condition
* try {
* if (cond.attempt(10)) { // try the condition for 10 ms
* try {
* // ... method body
* }
* finally {
* cond.release()
* }
* }
* }
* catch (InterruptedException ex) {
* // ... evasive action
* }
* }
* }
*
* Syncs may be used in somewhat tedious but more flexible replacements
* for built-in Java synchronized blocks. For example:
*
* class HandSynched {
* private double state_ = 0.0;
* private final Sync lock; // use lock type supplied in constructor
* public HandSynched(Sync l) { lock = l; }
*
* public void changeState(double d) {
* try {
* lock.acquire();
* try { state_ = updateFunction(d); }
* finally { lock.release(); }
* }
* catch(InterruptedException ex) { }
* }
*
* public double getState() {
* double d = 0.0;
* try {
* lock.acquire();
* try { d = accessFunction(state_); }
* finally { lock.release(); }
* }
* catch(InterruptedException ex){}
* return d;
* }
* private double updateFunction(double d) { ... }
* private double accessFunction(double d) { ... }
* }
*
* If you have a lot of such methods, and they take a common
* form, you can standardize this using wrappers. Some of these
* wrappers are standardized in LockedExecutor, but you can make others.
* For example:
*
* class HandSynchedV2 {
* private double state_ = 0.0;
* private final Sync lock; // use lock type supplied in constructor
* public HandSynchedV2(Sync l) { lock = l; }
*
* protected void runSafely(Runnable r) {
* try {
* lock.acquire();
* try { r.run(); }
* finally { lock.release(); }
* }
* catch (InterruptedException ex) { // propagate without throwing
* Thread.currentThread().interrupt();
* }
* }
*
* public void changeState(double d) {
* runSafely(new Runnable() {
* public void run() { state_ = updateFunction(d); }
* });
* }
* // ...
* }
*
*
* class Cell {
* long value;
* Sync lock = ... // some sync implementation class
* void swapValue(Cell other) {
* for (;;) {
* try {
* lock.acquire();
* try {
* if (other.lock.attempt(100)) {
* try {
* long t = value;
* value = other.value;
* other.value = t;
* return;
* }
* finally { other.lock.release(); }
* }
* }
* finally { lock.release(); }
* }
* catch (InterruptedException ex) { return; }
* }
* }
* }
*
*
* class Cell {
* long value;
* Sync lock = ...;
* private static boolean trySwap(Cell a, Cell b) {
* a.lock.acquire();
* try {
* if (!b.lock.attempt(0))
* return false;
* try {
* long t = a.value;
* a.value = b.value;
* b.value = t;
* return true;
* }
* finally { other.lock.release(); }
* }
* finally { lock.release(); }
* return false;
* }
*
* void swapValue(Cell other) {
* try {
* while (!trySwap(this, other) &&
* !tryswap(other, this))
* Thread.sleep(1);
* }
* catch (InterruptedException ex) { return; }
* }
*}
*
*
* if (!c.attempt(timeval)) throw new TimeoutException(timeval);
*
* synchronized
methods or blocks,
* and so entail the memory operations described in JLS
* chapter 17 which ensure that variables are loaded and flushed
* within before/after constructions.
*
* class X {
* Sync lock = ...
* void spinUntilAcquired() throws InterruptedException {
* // Two phase.
* // First spin without pausing.
* int purespins = 10;
* for (int i = 0; i < purespins; ++i) {
* if (lock.attempt(0))
* return true;
* }
* // Second phase - use timed waits
* long waitTime = 1; // 1 millisecond
* for (;;) {
* if (lock.attempt(waitTime))
* return true;
* else
* waitTime = waitTime * 3 / 2 + 1; // increase 50%
* }
* }
* }
*
*
*
* Different implementation classes differ in policies surrounding
* which threads to prefer when there is
* contention. By far, the most commonly useful policy is
* WriterPreferenceReadWriteLock. The other implementations
* are targeted for less common, niche applications.
*
* class X {
* ReadWriteLock rw;
* // ...
*
* public void read() throws InterruptedException {
* rw.readLock().acquire();
* try {
* // ... do the read
* }
* finally {
* rw.readlock().release()
* }
* }
*
*
* public void write() throws InterruptedException {
* rw.writeLock().acquire();
* try {
* // ... do the write
* }
* finally {
* rw.writelock().release()
* }
* }
* }
*
* @see Sync
* setRunPriorities
to either
* increase or decrease the priorities of active threads, which
* may interact with group size choice.
*
* class Tasks {
* static FJTaskRunnerGroup group;
* public void initialize(int groupsize) {
* group = new FJTaskRunnerGroup(groupSize);
* }
* // ...
* }
*
* Alternatively, you can make new groups on the fly and use them only for
* particular task sets. This is more flexible,,
* and leads to more controllable and deterministic execution patterns,
* but it encounters greater overhead on startup. Also, to reclaim
* system resources, you should
* call FJTaskRunnerGroup.interruptAll
when you are done
* using one-shot groups. Otherwise, because FJTaskRunners set
* Thread.isDaemon
* status, they will not normally be reclaimed until program termination.
* execute
,
* which starts a task processed by FJTaskRunner threads,
* and invoke
, which starts one and waits for completion.
* For example, you might extend the above FJTasks
* class to support a task-based computation, say, the
* Fib
class from the FJTask
documentation:
*
* class Tasks { // continued
* // ...
* static int fib(int n) {
* try {
* Fib f = new Fib(n);
* group.invoke(f);
* return f.getAnswer();
* }
* catch (InterruptedException ex) {
* throw new Error("Interrupted during computation");
* }
* }
* }
*
* stats()
can be used to monitor performance.
* Both FJTaskRunnerGroup and FJTaskRunner may be compiled with
* the compile-time constant COLLECT_STATS set to false. In this
* case, various simple counts reported in stats() are not collected.
* On platforms tested,
* this leads to such a tiny performance improvement that there is
* very little motivation to bother.
*
* FJTask.Wrap
.
* @exception InterruptedException if current Thread is
* currently interrupted
**/
public void execute(Runnable r) throws InterruptedException {
if (r instanceof FJTask) {
entryQueue.put((FJTask)r);
}
else {
entryQueue.put(new FJTask.Wrap(r));
}
signalNewTask();
}
/**
* Specialized form of execute called only from within FJTasks
**/
public void executeTask(FJTask t) {
try {
entryQueue.put(t);
signalNewTask();
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
/**
* Start a task and wait it out. Returns when the task completes.
* @exception InterruptedException if current Thread is
* interrupted before completion of the task.
**/
public void invoke(Runnable r) throws InterruptedException {
InvokableFJTask w = new InvokableFJTask(r);
entryQueue.put(w);
signalNewTask();
w.awaitTermination();
}
/**
* Try to shut down all FJTaskRunner threads in this group
* by interrupting them all. This method is designed
* to be used during cleanup when it is somehow known
* that all threads are idle.
* FJTaskRunners only
* check for interruption when they are not otherwise
* processing a task (and its generated subtasks,
* if any), so if any threads are active, shutdown may
* take a while, and may lead to unpredictable
* task processing.
**/
public void interruptAll() {
// paranoically interrupt current thread last if in group.
Thread current = Thread.currentThread();
boolean stopCurrent = false;
for (int i = 0; i < threads.length; ++i) {
Thread t = threads[i];
if (t == current)
stopCurrent = true;
else
t.interrupt();
}
if (stopCurrent)
current.interrupt();
}
/**
* Set the priority to use while a FJTaskRunner is
* polling for new tasks to perform. Default
* is currently Thread.MIN_PRIORITY+1. The value
* set may not go into effect immediately, but
* will be used at least the next time a thread scans for work.
**/
public synchronized void setScanPriorities(int pri) {
for (int i = 0; i < threads.length; ++i) {
FJTaskRunner t = threads[i];
t.setScanPriority(pri);
if (!t.active) t.setPriority(pri);
}
}
/**
* Set the priority to use while a FJTaskRunner is
* actively running tasks. Default
* is the priority that was in effect by the thread that
* constructed this FJTaskRunnerGroup. Setting this value
* while threads are running may momentarily result in
* them running at this priority even when idly waiting for work.
**/
public synchronized void setRunPriorities(int pri) {
for (int i = 0; i < threads.length; ++i) {
FJTaskRunner t = threads[i];
t.setRunPriority(pri);
if (t.active) t.setPriority(pri);
}
}
/** Return the number of FJTaskRunner threads in this group **/
public int size() { return threads.length; }
/**
* Return the number of threads that are not idly waiting for work.
* Beware that even active threads might not be doing any useful
* work, but just spinning waiting for other dependent tasks.
* Also, since this is just a snapshot value, some tasks
* may be in the process of becoming idle.
**/
public synchronized int getActiveCount() { return activeCount; }
/**
* Prints various snapshot statistics to System.out.
*
*
*
*
*
*
**/
public void stats() {
long time = System.currentTimeMillis() - initTime;
double secs = ((double)time) / 1000.0;
long totalRuns = 0;
long totalScans = 0;
long totalSteals = 0;
System.out.print("Thread" +
"\tQ Cap" +
"\tScans" +
"\tNew" +
"\tRuns" +
"\n");
for (int i = 0; i < threads.length; ++i) {
FJTaskRunner t = threads[i];
int truns = t.runs;
totalRuns += truns;
int tscans = t.scans;
totalScans += tscans;
int tsteals = t.steals;
totalSteals += tsteals;
String star = (getActive(t))? "*" : " ";
System.out.print("T" + i + star +
"\t" + t.deqSize() +
"\t" + tscans +
"\t" + tsteals +
"\t" + truns +
"\n");
}
System.out.print("Total" +
"\t " +
"\t" + totalScans +
"\t" + totalSteals +
"\t" + totalRuns +
"\n");
System.out.print("Execute: " + entries);
System.out.print("\tTime: " + secs);
long rps = 0;
if (secs != 0) rps = Math.round((double)(totalRuns) / secs);
System.out.println("\tRate: " + rps);
}
/* ------------ Methods called only by FJTaskRunners ------------- */
/**
* Return the array of threads in this group.
* Called only by FJTaskRunner.scan().
**/
protected FJTaskRunner[] getArray() { return threads; }
/**
* Return a task from entry queue, or null if empty.
* Called only by FJTaskRunner.scan().
**/
protected FJTask pollEntryQueue() {
try {
FJTask t = (FJTask)(entryQueue.poll(0));
return t;
}
catch(InterruptedException ex) { // ignore interrupts
Thread.currentThread().interrupt();
return null;
}
}
/**
* Return active status of t.
* Per-thread active status can only be accessed and
* modified via synchronized method here in the group class.
**/
protected synchronized boolean getActive(FJTaskRunner t) {
return t.active;
}
/**
* Set active status of thread t to true, and notify others
* that might be waiting for work.
**/
protected synchronized void setActive(FJTaskRunner t) {
if (!t.active) {
t.active = true;
++activeCount;
if (nstarted < threads.length)
threads[nstarted++].start();
else
notifyAll();
}
}
/**
* Set active status of thread t to false.
**/
protected synchronized void setInactive(FJTaskRunner t) {
if (t.active) {
t.active = false;
--activeCount;
}
}
/**
* The number of times to scan other threads for tasks
* before transitioning to a mode where scans are
* interleaved with sleeps (actually timed waits).
* Upon transition, sleeps are for duration of
* scans / SCANS_PER_SLEEP milliseconds.
*
* class Pool {
* static final MAX_AVAILABLE = 100;
* private final Semaphore available = new Semaphore(MAX_AVAILABLE);
*
* public Object getItem() throws InterruptedException { // no synch
* available.acquire();
* return getNextAvailableItem();
* }
*
* public void putItem(Object x) { // no synch
* if (markAsUnused(x))
* available.release();
* }
*
* // Not a particularly efficient data structure; just for demo
*
* protected Object[] items = ... whatever kinds of items being managed
* protected boolean[] used = new boolean[MAX_AVAILABLE];
*
* protected synchronized Object getNextAvailableItem() {
* for (int i = 0; i < MAX_AVAILABLE; ++i) {
* if (!used[i]) {
* used[i] = true;
* return items[i];
* }
* }
* return null; // not reached
* }
*
* protected synchronized boolean markAsUnused(Object item) {
* for (int i = 0; i < MAX_AVAILABLE; ++i) {
* if (item == items[i]) {
* if (used[i]) {
* used[i] = false;
* return true;
* }
* else
* return false;
* }
* }
* return false;
* }
*
* }
*
* release(n)
is
* equivalent in effect to:
*
* for (int i = 0; i < n; ++i) release();
*
*
* class ImageRenderer { Image render(byte[] raw); }
* class App {
* Executor executor = ...
* ImageRenderer renderer = ...
* void display(byte[] rawimage) {
* try {
* FutureResult futureImage = new FutureResult();
* Runnable command = futureImage.setter(new Callable() {
* public Object call() { return renderer.render(rawImage); }
* });
* executor.execute(command);
* drawBorders(); // do other things while executing
* drawCaption();
* drawImage((Image)(futureImage.get())); // use future
* }
* catch (InterruptedException ex) { return; }
* catch (InvocationTargetException ex) { cleanup(); return; }
* }
* }
*
*
* class Worker implements Runnable {
* private final Latch startSignal;
* Worker(Latch l) { startSignal = l; }
* public void run() {
* startSignal.acquire();
* doWork();
* }
* void doWork() { ... }
* }
*
* class Driver { // ...
* void main() {
* Latch go = new Latch();
* for (int i = 0; i < N; ++i) // make threads
* new Thread(new Worker(go)).start();
* doSomethingElse(); // don't let run yet
* go.release(); // let all threads proceed
* }
* }
*
* [ Introduction to this package. ]
*
* The possibly mutative writer operations (which are also
* the set of operations that are allowed to throw
* UnsupportedOperationException) are:
*
*
*
*
*
* synchronizationFailures()
.
* Non-zero values may indicate serious program errors.
* unprotectedIterator
* that can be used in conjunction with the readerSync
or
* writerSync
methods to perform locked traversals. For example,
* to protect a block of reads:
*
* Sync lock = coll.readerSync();
* try {
* lock.acquire();
* try {
* Iterator it = coll.unprotectedIterator();
* while (it.hasNext())
* System.out.println(it.next());
* }
* finally {
* lock.release();
* }
* }
* catch (InterruptedException ex) { ... }
*
* If you need to protect blocks of writes, you must use some
* form of reentrant lock (for example ReentrantLock
* or ReentrantWriterPreferenceReadWriteLock
) as the Sync
* for the collection in order to allow mutative methods to proceed
* while the current thread holds the lock. For example, you might
* need to hold a write lock during an initialization sequence:
*
* Collection c = new SyncCollection(new ArrayList(),
* new ReentrantWriterPreferenceReadWriteLock());
* // ...
* c.writeLock().acquire();
* try {
* for (...) {
* Object x = someStream.readObject();
* c.add(x); // would block if writeLock not reentrant
* }
* }
* catch (IOException iox) {
* ...
* }
* finally {
* c.writeLock().release();
* }
* catch (InterruptedException ex) { ... }
*
*
* Mutex lock = new Mutex();
* TimeoutSync timedLock = new TimeoutSync(lock, 1000); // 1 sec timeouts
* Collection c = new SyncCollection(new HashSet(), timedlock);
*
*
* ReadWriteLock rwl = new WriterPreferenceReadWriteLock();
* Sync rlock = new TimeoutSync(rwl.readLock(), 100);
* Sync wlock = new TimeoutSync(rwl.writeLock(), 100);
* Collection c = new SyncCollection(new HashSet(), rlock, wlock);
*
*
* class X {
* Collection c;
*
* static class CollectionObserver implements ObservableSync.SyncObserver {
* public void onAcquire(Object arg) {
* Collection coll = (Collection) arg;
* System.out.println("Starting operation on" + coll);
* // Other plausible responses include performing integrity
* // checks on the collection, updating displays, etc
* }
* public void onRelease(Object arg) {
* Collection coll = (Collection) arg;
* System.out.println("Finished operation on" + coll);
* }
* }
*
* X() {
* ObservableSync s = new ObservableSync();
* c = new SyncCollection(new HashSet(), s);
* s.setNotificationArgument(c);
* CollectionObserver obs = new CollectionObserver();
* s.attach(obs);
* }
* ...
* }
*
*
*
* Collection c = new SyncCollection(new ArrayList(), new Mutex());
*
**/
public SyncCollection(Collection collection, Sync sync) {
this (collection, sync, sync);
}
/**
* Create a new SyncCollection protecting the given collection,
* and using the given ReadWriteLock to control reader and writer methods.
*
* Collection c = new SyncCollection(new HashSet(),
* new WriterPreferenceReadWriteLock());
*
**/
public SyncCollection(Collection collection, ReadWriteLock rwl) {
this (collection, rwl.readLock(), rwl.writeLock());
}
/**
* Create a new SyncCollection protecting the given collection,
* and using the given pair of locks to control reader and writer methods.
**/
public SyncCollection(Collection collection, Sync readLock, Sync writeLock) {
c_ = collection;
rd_ = readLock;
wr_ = writeLock;
}
/**
* Return the Sync object managing read-only operations
**/
public Sync readerSync() {
return rd_;
}
/**
* Return the Sync object managing mutative operations
**/
public Sync writerSync() {
return wr_;
}
/**
* Return the number of synchronization failures for read-only operations
**/
public long syncFailures() {
return syncFailures_.get();
}
/** Try to acquire sync before a reader operation; record failure **/
protected boolean beforeRead() {
try {
rd_.acquire();
return false;
}
catch (InterruptedException ex) {
syncFailures_.increment();
return true;
}
}
/** Clean up after a reader operation **/
protected void afterRead(boolean wasInterrupted) {
if (wasInterrupted) {
Thread.currentThread().interrupt();
}
else
rd_.release();
}
public int size() {
boolean wasInterrupted = beforeRead();
try {
return c_.size();
}
finally {
afterRead(wasInterrupted);
}
}
public boolean isEmpty() {
boolean wasInterrupted = beforeRead();
try {
return c_.isEmpty();
}
finally {
afterRead(wasInterrupted);
}
}
public boolean contains(Object o) {
boolean wasInterrupted = beforeRead();
try {
return c_.contains(o);
}
finally {
afterRead(wasInterrupted);
}
}
public Object[] toArray() {
boolean wasInterrupted = beforeRead();
try {
return c_.toArray();
}
finally {
afterRead(wasInterrupted);
}
}
public Object[] toArray(Object[] a) {
boolean wasInterrupted = beforeRead();
try {
return c_.toArray(a);
}
finally {
afterRead(wasInterrupted);
}
}
public boolean containsAll(Collection coll) {
boolean wasInterrupted = beforeRead();
try {
return c_.containsAll(coll);
}
finally {
afterRead(wasInterrupted);
}
}
public boolean add(Object o) {
try {
wr_.acquire();
try {
return c_.add(o);
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
public boolean remove(Object o) {
try {
wr_.acquire();
try {
return c_.remove(o);
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
public boolean addAll(Collection coll) {
try {
wr_.acquire();
try {
return c_.addAll(coll);
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
public boolean removeAll(Collection coll) {
try {
wr_.acquire();
try {
return c_.removeAll(coll);
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
public boolean retainAll(Collection coll) {
try {
wr_.acquire();
try {
return c_.retainAll(coll);
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
public void clear() {
try {
wr_.acquire();
try {
c_.clear();
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
/** Return the base iterator of the underlying collection **/
public Iterator unprotectedIterator() {
boolean wasInterrupted = beforeRead();
try {
return c_.iterator();
}
finally {
afterRead(wasInterrupted);
}
}
public Iterator iterator() {
boolean wasInterrupted = beforeRead();
try {
return new SyncCollectionIterator(c_.iterator());
}
finally {
afterRead(wasInterrupted);
}
}
public class SyncCollectionIterator implements Iterator {
protected final Iterator baseIterator_;
SyncCollectionIterator(Iterator baseIterator) {
baseIterator_ = baseIterator;
}
public boolean hasNext() {
boolean wasInterrupted = beforeRead();
try {
return baseIterator_.hasNext();
}
finally {
afterRead(wasInterrupted);
}
}
public Object next() {
boolean wasInterrupted = beforeRead();
try {
return baseIterator_.next();
}
finally {
afterRead(wasInterrupted);
}
}
public void remove() {
try {
wr_.acquire();
try {
baseIterator_.remove();
}
finally {
wr_.release();
}
}
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
throw new UnsupportedOperationException();
}
}
}
}
concurrent-dfsg-1.3.4/NullSync.java 0000644 0001750 0001750 00000002544 10202157355 017463 0 ustar wbaer wbaer 0000000 0000000 /*
File: NullSync.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
1Aug1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A No-Op implementation of Sync. Acquire never blocks,
* Attempt always succeeds, Release has no effect.
* However, acquire and release do detect interruption
* and throw InterruptedException. Also, the methods
* are synchronized, so preserve memory barrier properties
* of Syncs.
*
* class CachedData {
* Object data;
* volatile boolean cacheValid;
* ReentrantWriterPreferenceReadWriteLock rwl = ...
*
* void processCachedData() {
* rwl.readLock().acquire();
* if (!cacheValid) {
*
* // upgrade lock:
* rwl.readLock().release(); // must release first to obtain writelock
* rwl.writeLock().acquire();
* if (!cacheValid) { // recheck
* data = ...
* cacheValid = true;
* }
* // downgrade lock
* rwl.readLock().acquire(); // reacquire read without giving up lock
* rwl.writeLock().release(); // release write, still hold read
* }
*
* use(data);
* rwl.readLock().release();
* }
* }
*
*
*
*
*
* final
. This
* helps avoid the need to synchronize just to obtain the reference
* to the synchronized variable itself.
*
* static
variables. It almost
* always works out better to rely on synchronization internal
* to these objects, rather than class locks.
*
* Synchronized variables are always constructed holding an
* initial value of the associated type. Constructors also
* establish the lock to use for all methods:
*
*
*
* Each class supports several kinds of update methods:
*
*
* set
method that sets to a new value and returns
* previous value. For example, for a SynchronizedBoolean b,
* boolean old = b.set(true)
performs a test-and-set.
* commit
method that sets to new value only
* if currently holding a given value.
*
* For example, here is a class that uses an optimistic update
* loop to recompute a count variable represented as a
* SynchronizedInt.
*
* class X {
* private final SynchronizedInt count = new SynchronizedInt(0);
*
* static final int MAX_RETRIES = 1000;
*
* public boolean recomputeCount() throws InterruptedException {
* for (int i = 0; i < MAX_RETRIES; ++i) {
* int current = count.get();
* int next = compute(current);
* if (count.commit(current, next))
* return true;
* else if (Thread.interrupted())
* throw new InterruptedException();
* }
* return false;
* }
* int compute(int l) { ... some kind of computation ... }
* }
*
* swap
method that atomically swaps with another
* object of the same class using a deadlock-avoidance strategy.
*
*
* Integral types also support:
*
*
* Boolean types support:
*
*
* These cover most, but not all of the possible operators in Java.
* You can add more compute-and-set methods in subclasses. This
* is often a good way to avoid the need for ad-hoc synchronized
* blocks surrounding expressions.
*
* All Waitable
subclasses provide notifications on
* every value update, and support guarded methods of the form
* when
predicate, that wait until the
* predicate hold, then optionally run any Runnable action
* within the lock, and then return. All types support:
*
*
* (If the action argument is null, these return immediately
* after the predicate holds.)
* Numerical types also support
*
*
* The Waitable classes are not always spectacularly efficient since they
* provide notifications on all value changes. They are
* designed for use in contexts where either performance is not an
* overriding issue, or where nearly every update releases guarded
* waits anyway.
*
* This class implements Executor, and provides an execute
* method that runs the runnable within the lock.
* Cloneable
and Comparable
.
* Implementations of the corresponding
* methods either use default mechanics, or use methods that closely
* correspond to their java.lang analogs. SynchronizedRef does not
* implement any of these standard interfaces because there are
* many cases where it would not make sense. However, you can
* easily make simple subclasses that add the appropriate declarations.
*
* put
operations may block when the
* capacity is reached. Various implementations may have
* intrinsically hard-wired capacities, capacities that are fixed upon
* construction, or dynamically adjustable capacities.
* @see DefaultChannelCapacity
* execute(Runnable command)
, which can be
* called instead of directly creating threads to execute commands.
*
*
*
*
*
* These goals introduce a number of policy parameters that are
* encapsulated in this class. All of these parameters have defaults
* and are tunable, either via get/set methods, or, in cases where
* decisions should hold across lifetimes, via methods that can be
* easily overridden in subclasses. The main, most commonly set
* parameters can be established in constructors. Policy choices
* across these dimensions can and do interact. Be careful, and
* please read this documentation completely before using! See also
* the usage examples below.
*
*
*
* execute
request arrives. The default
* value is (for all practical purposes) infinite --
* Integer.MAX_VALUE
, so should be set in the
* constructor or the set method unless you are just using the pool
* to minimize construction overhead. Because task handoffs to idle
* worker threads require synchronization that in turn relies on JVM
* scheduling policies to ensure progress, it is possible that a new
* thread will be created even though an existing worker thread has
* just become idle but has not progressed to the point at which it
* can accept a new task. This phenomenon tends to occur on some
* JVMs when bursts of short tasks are executed. execute
requests to
* block. There are four supported policies for handling this
* problem, and mechanics (based on the Strategy Object pattern) to
* allow others in subclasses:
*
*
* Other plausible policies include raising the maximum pool size
* after checking with some other objects that this is OK. execute
request
* runs the task itself. This policy helps guard against lockup.
* execute
. If for some reason you would instead like
* to make per-call decisions, you could add variant versions of the
* execute
method (for example,
* executeIfWouldNotBlock
) in subclasses.
* class MyPool {
* // initialize to use a maximum of 8 threads.
* static PooledExecutor pool = new PooledExecutor(8);
* }
*
* Here are some sample variants in initialization:
*
*
*
*
* pool = new PooledExecutor(new BoundedBuffer(10), 100);
* pool.setMinimumPoolSize(4);
*
*
* pool = new PooledExecutor(new BoundedBuffer(10), 100);
* pool.setMinimumPoolSize(4);
* pool.setKeepAliveTime(1000 * 60 * 5);
* pool.createThreads(9);
*
*
* pool = new PooledExecutor(new BoundedBuffer(10), 100);
* pool.setMinimumPoolSize(4);
* pool.setKeepAliveTime(1000 * 60 * 5);
* pool.abortWhenBlocked();
* pool.createThreads(9);
*
*
* pool = new PooledExecutor(new LinkedQueue());
* pool.setKeepAliveTime(-1); // live forever
* pool.createThreads(5);
*
*
* List tasks = pool.drain();
* for (Iterator it = tasks.iterator(); it.hasNext();)
* ( (Runnable)(it.next()) ).run();
*
**/
public List drain() {
boolean wasInterrupted = false;
Vector tasks = new Vector();
for (;;) {
try {
Object x = handOff_.poll(0);
if (x == null)
break;
else
tasks.addElement(x);
}
catch (InterruptedException ex) {
wasInterrupted = true; // postpone re-interrupt until drained
}
}
if (wasInterrupted) Thread.currentThread().interrupt();
return tasks;
}
/**
* Cleanup method called upon termination of worker thread.
**/
protected synchronized void workerDone(Worker w) {
threads_.remove(w);
if (--poolSize_ == 0 && shutdown_) {
maximumPoolSize_ = minimumPoolSize_ = 0; // disable new threads
notifyAll(); // notify awaitTerminationAfterShutdown
}
// Create a replacement if needed
if (poolSize_ == 0 || poolSize_ < minimumPoolSize_) {
try {
Runnable r = (Runnable)(handOff_.poll(0));
if (r != null && !shutdown_) // just consume task if shut down
addThread(r);
} catch(InterruptedException ie) {
return;
}
}
}
/**
* Get a task from the handoff queue, or null if shutting down.
**/
protected Runnable getTask() throws InterruptedException {
long waitTime;
synchronized(this) {
if (poolSize_ > maximumPoolSize_) // Cause to die if too many threads
return null;
waitTime = (shutdown_)? 0 : keepAliveTime_;
}
if (waitTime >= 0)
return (Runnable)(handOff_.poll(waitTime));
else
return (Runnable)(handOff_.take());
}
/**
* Class defining the basic run loop for pooled threads.
**/
protected class Worker implements Runnable {
protected Runnable firstTask_;
protected Worker(Runnable firstTask) { firstTask_ = firstTask; }
public void run() {
try {
Runnable task = firstTask_;
firstTask_ = null; // enable GC
if (task != null) {
task.run();
task = null;
}
while ( (task = getTask()) != null) {
task.run();
task = null;
}
}
catch (InterruptedException ex) { } // fall through
finally {
workerDone(this);
}
}
}
/**
* Class for actions to take when execute() blocks. Uses Strategy
* pattern to represent different actions. You can add more in
* subclasses, and/or create subclasses of these. If so, you will
* also want to add or modify the corresponding methods that set the
* current blockedExectionHandler_.
**/
public interface BlockedExecutionHandler {
/**
* Return true if successfully handled so, execute should
* terminate; else return false if execute loop should be retried.
**/
boolean blockedAction(Runnable command) throws InterruptedException;
}
/** Class defining Run action. **/
protected class RunWhenBlocked implements BlockedExecutionHandler {
public boolean blockedAction(Runnable command) {
command.run();
return true;
}
}
/**
* Set the policy for blocked execution to be that the current
* thread executes the command if there are no available threads in
* the pool.
**/
public void runWhenBlocked() {
setBlockedExecutionHandler(new RunWhenBlocked());
}
/** Class defining Wait action. **/
protected class WaitWhenBlocked implements BlockedExecutionHandler {
public boolean blockedAction(Runnable command) throws InterruptedException{
synchronized(PooledExecutor.this) {
if (shutdown_)
return true;
}
handOff_.put(command);
return true;
}
}
/**
* Set the policy for blocked execution to be to wait until a thread
* is available, unless the pool has been shut down, in which case
* the action is discarded.
**/
public void waitWhenBlocked() {
setBlockedExecutionHandler(new WaitWhenBlocked());
}
/** Class defining Discard action. **/
protected class DiscardWhenBlocked implements BlockedExecutionHandler {
public boolean blockedAction(Runnable command) {
return true;
}
}
/**
* Set the policy for blocked execution to be to return without
* executing the request.
**/
public void discardWhenBlocked() {
setBlockedExecutionHandler(new DiscardWhenBlocked());
}
/** Class defining Abort action. **/
protected class AbortWhenBlocked implements BlockedExecutionHandler {
public boolean blockedAction(Runnable command) {
throw new RuntimeException("Pool is blocked");
}
}
/**
* Set the policy for blocked execution to be to
* throw a RuntimeException.
**/
public void abortWhenBlocked() {
setBlockedExecutionHandler(new AbortWhenBlocked());
}
/**
* Class defining DiscardOldest action. Under this policy, at most
* one old unhandled task is discarded. If the new task can then be
* handed off, it is. Otherwise, the new task is run in the current
* thread (i.e., RunWhenBlocked is used as a backup policy.)
**/
protected class DiscardOldestWhenBlocked implements BlockedExecutionHandler {
public boolean blockedAction(Runnable command) throws InterruptedException{
handOff_.poll(0);
if (!handOff_.offer(command, 0))
command.run();
return true;
}
}
/**
* Set the policy for blocked execution to be to discard the oldest
* unhandled request
**/
public void discardOldestWhenBlocked() {
setBlockedExecutionHandler(new DiscardOldestWhenBlocked());
}
/**
* Arrange for the given command to be executed by a thread in this
* pool. The method normally returns when the command has been
* handed off for (possibly later) execution.
**/
public void execute(Runnable command) throws InterruptedException {
for (;;) {
synchronized(this) {
if (!shutdown_) {
int size = poolSize_;
// Ensure minimum number of threads
if (size < minimumPoolSize_) {
addThread(command);
return;
}
// Try to give to existing thread
if (handOff_.offer(command, 0)) {
return;
}
// If cannot handoff and still under maximum, create new thread
if (size < maximumPoolSize_) {
addThread(command);
return;
}
}
}
// Cannot hand off and cannot create -- ask for help
if (getBlockedExecutionHandler().blockedAction(command)) {
return;
}
}
}
}
concurrent-dfsg-1.3.4/Barrier.java 0000644 0001750 0001750 00000003774 10202157355 017310 0 ustar wbaer wbaer 0000000 0000000
/*
File: Barrier.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* Barriers serve
* as synchronization points for groups of threads that
* must occasionally wait for each other.
* Barriers may support any of several methods that
* accomplish this synchronization. This interface
* merely expresses their minimal commonalities:
*
*
* parties
-- the number of threads
* that must meet at the barrier point. (In all current
* implementations, this
* value is fixed upon construction of the Barrier.)
* broken
if
* one or more threads leave a barrier point prematurely,
* generally due to interruption or timeout. Corresponding
* synchronization methods in barriers fail, throwing
* BrokenBarrierException for other threads
* when barriers are in broken states.
* Wrap(Runnable r)
* can be used to
* wrap an existing Runnable object in a FJTask.
* FJTaskRunnerGroup.execute(FJTask)
can be used to
* initiate a FJTask from a non-FJTask thread.
* And FJTaskRunnerGroup.invoke(FJTask)
can be used to initiate
* a FJTask and then wait for it to complete before returning.
* These are the only entry-points from normal threads to FJTasks.
* Most FJTask methods themselves may only be called from within running FJTasks.
* They throw ClassCastExceptions if they are not,
* reflecting the fact that these methods
* can only be executed using FJTaskRunner threads, not generic
* java.lang.Threads.
*
*
* while(!isDone()) yield();
* @exception ClassCastException if caller thread is not
* running in a FJTaskRunner thread.
**/
public void join() { getFJTaskRunner().taskJoin(this); }
/**
* Immediately execute task t by calling its run method. Has no
* effect if t has already been run or has been cancelled.
* It is equivalent to calling t.run except that it
* deals with completion status, so should always be used
* instead of directly calling run.
* The method can be useful
* when a computation has been packaged as a FJTask, but you just need to
* directly execute its body from within some other task.
**/
public static void invoke(FJTask t) {
if (!t.isDone()) {
t.run();
t.setDone();
}
}
/**
* Fork both tasks and then wait for their completion. It behaves as:
*
* task1.fork(); task2.fork(); task2.join(); task1.join();
*
* As a simple classic example, here is
* a class that computes the Fibonacci function:
*
* public class Fib extends FJTask {
*
* // Computes fibonacci(n) = fibonacci(n-1) + fibonacci(n-2); for n> 1
* // fibonacci(0) = 0;
* // fibonacci(1) = 1.
*
* // Value to compute fibonacci function for.
* // It is replaced with the answer when computed.
* private volatile int number;
*
* public Fib(int n) { number = n; }
*
* public int getAnswer() {
* if (!isDone()) throw new Error("Not yet computed");
* return number;
* }
*
* public void run() {
* int n = number;
* if (n > 1) {
* Fib f1 = new Fib(n - 1);
* Fib f2 = new Fib(n - 2);
*
* coInvoke(f1, f2); // run these in parallel
*
* // we know f1 and f2 are computed, so just directly access numbers
* number = f1.number + f2.number;
* }
* }
*
* public static void main(String[] args) { // sample driver
* try {
* int groupSize = 2; // 2 worker threads
* int num = 35; // compute fib(35)
* FJTaskRunnerGroup group = new FJTaskRunnerGroup(groupSize);
* Fib f = new Fib(num);
* group.invoke(f);
* int result = f.getAnswer();
* System.out.println(" Answer: " + result);
* }
* catch (InterruptedException ex) {
* System.out.println("Interrupted");
* }
* }
* }
*
*
* @exception ClassCastException if caller thread is not
* running in a FJTaskRunner thread.
**/
public static void coInvoke(FJTask task1, FJTask task2) {
getFJTaskRunner().coInvoke(task1, task2);
}
/**
* Fork all tasks in array, and await their completion.
* Behaviorally equivalent to:
*
* for (int i = 0; i < tasks.length; ++i) tasks[i].fork();
* for (int i = 0; i < tasks.length; ++i) tasks[i].join();
*
**/
public static void coInvoke(FJTask[] tasks) {
getFJTaskRunner().coInvoke(tasks);
}
/**
* A FJTask that holds a Runnable r, and calls r.run when executed.
* The class is a simple utilty to allow arbitrary Runnables
* to be used as FJTasks.
**/
public static class Wrap extends FJTask {
protected final Runnable runnable;
public Wrap(Runnable r) { runnable = r; }
public void run() { runnable.run(); }
}
/**
* A new Seq
, when executed,
* invokes each task provided in the constructor, in order.
* The class is a simple utility
* that makes it easier to create composite FJTasks.
**/
public static class Seq extends FJTask {
protected final FJTask[] tasks;
/**
* Construct a Seq that, when executed, will process each of the
* tasks in the tasks array in order
**/
public Seq(FJTask[] tasks) {
this.tasks = tasks;
}
/**
* Two-task constructor, for compatibility with previous release.
**/
public Seq(FJTask task1, FJTask task2) {
this.tasks = new FJTask[] { task1, task2 };
}
public void run() {
for (int i = 0; i < tasks.length; ++i) FJTask.invoke(tasks[i]);
}
}
/**
* Construct and return a FJTask object that, when executed, will
* invoke the tasks in the tasks array in array order
**/
public static FJTask seq(FJTask[] tasks) {
return new Seq(tasks);
}
/**
* A new Par
, when executed,
* runs the tasks provided in the constructor in parallel using
* coInvoke(tasks).
* The class is a simple utility
* that makes it easier to create composite FJTasks.
**/
public static class Par extends FJTask {
protected final FJTask[] tasks;
/**
* Construct a Seq that, when executed, will process each of the
* tasks in the tasks array in parallel
**/
public Par(FJTask[] tasks) {
this.tasks = tasks;
}
/**
* Two-task constructor, for compatibility with previous release.
**/
public Par(FJTask task1, FJTask task2) {
this.tasks = new FJTask[] { task1, task2 };
}
public void run() {
FJTask.coInvoke(tasks);
}
}
/**
* Construct and return a FJTask object that, when executed, will
* invoke the tasks in the tasks array in parallel using coInvoke
**/
public static FJTask par(FJTask[] tasks) {
return new Par(tasks);
}
/**
* A new Seq2(task1, task2)
, when executed,
* invokes task1 and then task2, in order.
* The class is a simple utility
* that makes it easier to create composite Tasks.
**/
public static class Seq2 extends FJTask {
protected final FJTask fst;
protected final FJTask snd;
public Seq2(FJTask task1, FJTask task2) {
fst = task1;
snd = task2;
}
public void run() {
FJTask.invoke(fst);
FJTask.invoke(snd);
}
}
/**
* Construct and return a FJTask object that, when executed, will
* invoke task1 and task2, in order
**/
public static FJTask seq(FJTask task1, FJTask task2) {
return new Seq2(task1, task2);
}
/**
* A new Par(task1, task2)
, when executed,
* runs task1 and task2 in parallel using coInvoke(task1, task2).
* The class is a simple utility
* that makes it easier to create composite Tasks.
**/
public static class Par2 extends FJTask {
protected final FJTask fst;
protected final FJTask snd;
public Par2(FJTask task1, FJTask task2) {
fst = task1;
snd = task2;
}
public void run() {
FJTask.coInvoke(fst, snd);
}
}
/**
* Construct and return a FJTask object that, when executed, will
* invoke task1 and task2, in parallel
**/
public static FJTask par(FJTask task1, FJTask task2) {
return new Par2(task1, task2);
}
}
concurrent-dfsg-1.3.4/SynchronizedRef.java 0000644 0001750 0001750 00000005325 10202157355 021030 0 ustar wbaer wbaer 0000000 0000000 /*
File: SynchronizedRef.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
import java.io.*;
/**
* A simple class maintaining a single reference variable that
* is always accessed and updated under synchronization.
* execute
request is encountered. Also, if the
* thread is stopped for any reason (for example, after hitting
* an unrecoverable exception in an executing task), one is started
* upon encountering a new request, or if restart()
is
* invoked.
* Overview of package util.concurrent Release 1.3.4.
by Doug Lea
Plus some utilities and frameworks that build upon these.
Sync
-- locks, conditions
Channel
-- queues, buffers
Barrier
-- multi-party synchronization
SynchronizedVariable
-- atomic ints, refs etc
java.util.Collection
-- collections
Executor
-- replacements for direct use of Thread
http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html
following links from your local documentation, please check the
version number and get an update if you are running an outdated
version.
Installation
This package, currently declared as
is available in (tar.gz
format) or (zip
format).
EDU.oswego.cs.dl.util.concurrent
javac -d [SOMEWHERE IN YOUR CLASSPATH] *.java
Or use this ant build file donated by
Travell Perkins.
misc
directory can be built the
same way.
import EDU.oswego.cs.dl.util.concurrent.*
javadoc -public -d [BASE OF SOME JAVADOC PATH] *.java
Contents
acquire
, attempt(msecs)
, and
release
.
put
and take
, as well as
timeout-based offer
and poll
. To assist
efforts to use channels with somewhat greater type safety, Channel
is defined as a subinterface of Puttable and Takable, each defining only one side of
the channel. Also, the BoundedChannel subinterface is used
for channels with finite capacities.
execute
Runnable commands.
misc
directory
that might be of interest but aren't really part of this
package. They include:
If you would like to contribute other related classes, demos,
usage examples, etc., please contact me. People frequently write
me asking for such things.
Notes
package EDU.oswego.cs.dl.util.concurrent ;
class Random extends java.util.Random {
public Random() {super() ;}
public Random(long l) {super(l) ;}
public int nextInt(int i) {
int ii = (int)(i * nextDouble()) ;
if (ii >= i) {ii = i-1 ;} // should (almost?) never happen...
return ii ;
}
}
Some Questions and Answers about Design and Implementation
Thread.currentThread().interrupt()
to propagate
status.
void quietlyAcquire(Sync sync) {
boolean wasInterrupted = Thread.interrupted(); // record and clear
for (;;) {
try {
sync.acquire(); // or any other method throwing InterruptedException
break;
}
catch (InterruptedException ex) { // re-interrupted; try again
wasInterrupted = true;
}
}
if (wasInterrupted) { // re-establish interrupted state
Thread.currentThread().interrupt();
}
}
synchronized
method/block locks. On
some JVMs the cost is very low. (You can check approximate impact
using SynchronizationTimer.)
But, while Java VMs are getting much faster about
synchronized
locks, most of the classes in this
package rely heavily on wait/notify and interruption mechanics,
which are not currently as heavily optimized. (Also, they seem to
be subject to more variation in behavior than other Java
constructs.) Class implementations generally ignore the fact
that the JVM overhead for these operations might be slower than
you'd wish they were on some JVMs.
protected
?
Serializable
?
x
via synchronized(x) {
... }
?
synchronized(x)
and so probably ought never
use it.
EDU
..., not edu
?
Sources
History
concurrent-dfsg-1.3.4/ReentrantLock.java 0000644 0001750 0001750 00000007212 10202157355 020464 0 ustar wbaer wbaer 0000000 0000000 /*
File: ReentrantLock.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
5Aug1998 dl replaced int counters with longs
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A lock with the same semantics as builtin
* Java synchronized locks: Once a thread has a lock, it
* can re-obtain it any number of times without blocking.
* The lock is made available to other threads when
* as many releases as acquires have occurred.
*
release(n)
is
* equivalent in effect to:
*
* for (int i = 0; i < n; ++i) release();
*
*
* class CVBuffer implements BoundedChannel {
* private final Mutex mutex;
* private final CondVar notFull;
* private final CondVar notEmpty;
* private int count = 0;
* private int takePtr = 0;
* private int putPtr = 0;
* private final Object[] array;
*
* public CVBuffer(int capacity) {
* array = new Object[capacity];
* mutex = new Mutex();
* notFull = new CondVar(mutex);
* notEmpty = new CondVar(mutex);
* }
*
* public int capacity() { return array.length; }
*
* public void put(Object x) throws InterruptedException {
* mutex.acquire();
* try {
* while (count == array.length) {
* notFull.await();
* }
* array[putPtr] = x;
* putPtr = (putPtr + 1) % array.length;
* ++count;
* notEmpty.signal();
* }
* finally {
* mutex.release();
* }
* }
*
* public Object take() throws InterruptedException {
* Object x = null;
* mutex.acquire();
* try {
* while (count == 0) {
* notEmpty.await();
* }
* x = array[takePtr];
* array[takePtr] = null;
* takePtr = (takePtr + 1) % array.length;
* --count;
* notFull.signal();
* }
* finally {
* mutex.release();
* }
* return x;
* }
*
* public boolean offer(Object x, long msecs) throws InterruptedException {
* mutex.acquire();
* try {
* if (count == array.length) {
* notFull.timedwait(msecs);
* if (count == array.length)
* return false;
* }
* array[putPtr] = x;
* putPtr = (putPtr + 1) % array.length;
* ++count;
* notEmpty.signal();
* return true;
* }
* finally {
* mutex.release();
* }
* }
*
* public Object poll(long msecs) throws InterruptedException {
* Object x = null;
* mutex.acquire();
* try {
* if (count == 0) {
* notEmpty.timedwait(msecs);
* if (count == 0)
* return null;
* }
* x = array[takePtr];
* array[takePtr] = null;
* takePtr = (takePtr + 1) % array.length;
* --count;
* notFull.signal();
* }
* finally {
* mutex.release();
* }
* return x;
* }
* }
*
*
* @see Mutex
* Mutex
,
* but, for example, a Semaphore initialized to 1 also works.
* On the other hand, many other Sync implementations would not
* work here, so some care is required to supply a sensible
* synchronization object.
* In normal use, the mutex should be one that is used for all
* synchronization of the object using the CondVar. Generally,
* to prevent nested monitor lockouts, this
* object should not use any native Java synchronized blocks.
**/
public CondVar(Sync mutex) {
mutex_ = mutex;
}
/**
* Wait for notification. This operation at least momentarily
* releases the mutex. The mutex is always held upon return,
* even if interrupted.
* @exception InterruptedException if the thread was interrupted
* before or during the wait. However, if the thread is interrupted
* after the wait but during mutex re-acquisition, the interruption
* is ignored, while still ensuring
* that the currentThread's interruption state stays true, so can
* be probed by callers.
**/
public void await() throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
try {
synchronized(this) {
mutex_.release();
try {
wait();
}
catch (InterruptedException ex) {
notify();
throw ex;
}
}
}
finally {
// Must ignore interrupt on re-acquire
boolean interrupted = false;
for (;;) {
try {
mutex_.acquire();
break;
}
catch (InterruptedException ex) {
interrupted = true;
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
}
}
/**
* Wait for at most msecs for notification.
* This operation at least momentarily
* releases the mutex. The mutex is always held upon return,
* even if interrupted.
* @param msecs The time to wait. A value less than or equal to zero
* causes a momentarily release
* and re-acquire of the mutex, and always returns false.
* @return false if at least msecs have elapsed
* upon resumption; else true. A
* false return does NOT necessarily imply that the thread was
* not notified. For example, it might have been notified
* after the time elapsed but just before resuming.
* @exception InterruptedException if the thread was interrupted
* before or during the wait.
**/
public boolean timedwait(long msecs) throws InterruptedException {
if (Thread.interrupted()) throw new InterruptedException();
boolean success = false;
try {
synchronized(this) {
mutex_.release();
try {
if (msecs > 0) {
long start = System.currentTimeMillis();
wait(msecs);
success = System.currentTimeMillis() - start <= msecs;
}
}
catch (InterruptedException ex) {
notify();
throw ex;
}
}
}
finally {
// Must ignore interrupt on re-acquire
boolean interrupted = false;
for (;;) {
try {
mutex_.acquire();
break;
}
catch (InterruptedException ex) {
interrupted = true;
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
}
return success;
}
/**
* Notify a waiting thread.
* If one exists, a non-interrupted thread will return
* normally (i.e., not via InterruptedException) from await or timedwait.
**/
public synchronized void signal() {
notify();
}
/** Notify all waiting threads **/
public synchronized void broadcast() {
notifyAll();
}
}
concurrent-dfsg-1.3.4/Mutex.java 0000644 0001750 0001750 00000012222 10202157355 017010 0 ustar wbaer wbaer 0000000 0000000 /*
File: Mutex.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
11Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* A simple non-reentrant mutual exclusion lock.
* The lock is free upon construction. Each acquire gets the
* lock, and each release frees it. Releasing a lock that
* is already free has no effect.
*
*
* class Node {
* Object item;
* Node next;
* Mutex lock = new Mutex(); // each node keeps its own lock
*
* Node(Object x, Node n) { item = x; next = n; }
* }
*
* class List {
* protected Node head; // pointer to first node of list
*
* // Use plain java synchronization to protect head field.
* // (We could instead use a Mutex here too but there is no
* // reason to do so.)
* protected synchronized Node getHead() { return head; }
*
* boolean search(Object x) throws InterruptedException {
* Node p = getHead();
* if (p == null) return false;
*
* // (This could be made more compact, but for clarity of illustration,
* // all of the cases that can arise are handled separately.)
*
* p.lock.acquire(); // Prime loop by acquiring first lock.
* // (If the acquire fails due to
* // interrupt, the method will throw
* // InterruptedException now,
* // so there is no need for any
* // further cleanup.)
* for (;;) {
* if (x.equals(p.item)) {
* p.lock.release(); // release current before return
* return true;
* }
* else {
* Node nextp = p.next;
* if (nextp == null) {
* p.lock.release(); // release final lock that was held
* return false;
* }
* else {
* try {
* nextp.lock.acquire(); // get next lock before releasing current
* }
* catch (InterruptedException ex) {
* p.lock.release(); // also release current if acquire fails
* throw ex;
* }
* p.lock.release(); // release old lock now that new one held
* p = nextp;
* }
* }
* }
* }
*
* synchronized void add(Object x) { // simple prepend
* // The use of `synchronized' here protects only head field.
* // The method does not need to wait out other traversers
* // who have already made it past head.
*
* head = new Node(x, head);
* }
*
* // ... other similar traversal and update methods ...
* }
*
*
*
* The push, pop, and put are designed to only ever called by the
* current thread, and take (steal) is only ever called by
* other threads.
* All other operations are composites and variants of these,
* plus a few miscellaneous bookkeeping methods.
*
* Push task onto DEQ
*
*
* If DEQ is not empty,
* Pop a task and run it.
* Else if any other DEQ is not empty,
* Take ("steal") a task from it and run it.
* Else if the entry queue for our group is not empty,
* Take a task from it and run it.
* Else if current thread is otherwise idling
* If all threads are idling
* Wait for a task to be put on group entry queue
* Else
* Yield or Sleep for a while, and then retry
*
*
* 0 1 2 3 4 5 6 ...
* +-----+-----+-----+-----+-----+-----+-----+--
* | | t | t | t | t | | | ... deq array
* +-----+-----+-----+-----+-----+-----+-----+--
* ^ ^
* base top
* (incremented (incremented
* on take, on push
* decremented decremented
* on put) on pop)
*
* volatile
.
* Using volatile rather than synchronizing suffices here since
* each task accessed by a thread is either one that it
* created or one that has never seen before. Thus we cannot
* encounter any staleness problems executing run methods,
* although FJTask programmers must be still sure to either synch or use
* volatile for shared data within their run methods.
* base
and top
of the DEQ
* are declared as volatile. The main contention point with
* multiple FJTaskRunner threads occurs when one thread is trying
* to pop its own stack while another is trying to steal from it.
* This is handled via a specialization of Dekker's algorithm,
* in which the popping thread pre-decrements top
,
* and then checks it against base
.
* To be conservative in the face of JVMs that only partially
* honor the specification for volatile, the pop proceeds
* without synchronization only if there are apparently enough
* items for both a simultaneous pop and take to succeed.
* It otherwise enters a
* synchronized lock to check if the DEQ is actually empty,
* if so failing. The stealing thread
* does almost the opposite, but is set up to be less likely
* to win in cases of contention: Steals always run under synchronized
* locks in order to avoid conflicts with other ongoing steals.
* They pre-increment base
, and then check against
* top
. They back out (resetting the base index
* and failing to steal) if the
* DEQ is empty or is about to become empty by an ongoing pop.
* 0 ... deq.length
though.
* The current top element is always at top & (deq.length-1)
.
* To avoid integer overflow, top is reset down
* within bounds whenever it is noticed to be out out bounds;
* at worst when it is at 2 * deq.length
.
**/
protected volatile int top = 0;
/**
* Current base of DEQ. Acts like a take-pointer in an
* array-based bounded queue. Same bounds and usage as top.
**/
protected volatile int base = 0;
/**
* An extra object to synchronize on in order to
* achieve a memory barrier.
**/
protected final Object barrier = new Object();
/* ------------ Other BookKeeping ------------------- */
/**
* Record whether current thread may be processing a task
* (i.e., has been started and is not in an idle wait).
* Accessed, under synch, ONLY by FJTaskRunnerGroup, but the field is
* stored here for simplicity.
**/
protected boolean active = false;
/** Random starting point generator for scan() **/
protected final Random victimRNG;
/** Priority to use while scanning for work **/
protected int scanPriority = FJTaskRunnerGroup.DEFAULT_SCAN_PRIORITY;
/** Priority to use while running tasks **/
protected int runPriority;
/**
* Set the priority to use while scanning.
* We do not bother synchronizing access, since
* by the time the value is needed, both this FJTaskRunner
* and its FJTaskRunnerGroup will
* necessarily have performed enough synchronization
* to avoid staleness problems of any consequence.
**/
protected void setScanPriority(int pri) { scanPriority = pri; }
/**
* Set the priority to use while running tasks.
* Same usage and rationale as setScanPriority.
**/
protected void setRunPriority(int pri) { runPriority = pri; }
/**
* Compile-time constant for statistics gathering.
* Even when set, reported values may not be accurate
* since all are read and written without synchronization.
**/
static final boolean COLLECT_STATS = true;
// static final boolean COLLECT_STATS = false;
// for stat collection
/** Total number of tasks run **/
protected int runs = 0;
/** Total number of queues scanned for work **/
protected int scans = 0;
/** Total number of tasks obtained via scan **/
protected int steals = 0;
/* ------------ DEQ operations ------------------- */
/**
* Push a task onto DEQ.
* Called ONLY by current thread.
**/
protected final void push(final FJTask r) {
int t = top;
/*
This test catches both overflows and index wraps. It doesn't
really matter if base value is in the midst of changing in take.
As long as deq length is < 2^30, we are guaranteed to catch wrap in
time since base can only be incremented at most length times
between pushes (or puts).
*/
if (t < (base & (deq.length-1)) + deq.length) {
deq[t & (deq.length-1)].put(r);
top = t + 1;
}
else // isolate slow case to increase chances push is inlined
slowPush(r); // check overflow and retry
}
/**
* Handle slow case for push
**/
protected synchronized void slowPush(final FJTask r) {
checkOverflow();
push(r); // just recurse -- this one is sure to succeed.
}
/**
* Enqueue task at base of DEQ.
* Called ONLY by current thread.
* This method is currently not called from class FJTask. It could be used
* as a faster way to do FJTask.start, but most users would
* find the semantics too confusing and unpredictable.
**/
protected final synchronized void put(final FJTask r) {
for (;;) {
int b = base - 1;
if (top < b + deq.length) {
int newBase = b & (deq.length-1);
deq[newBase].put(r);
base = newBase;
if (b != newBase) { // Adjust for index underflow
int newTop = top & (deq.length-1);
if (newTop < newBase) newTop += deq.length;
top = newTop;
}
return;
}
else {
checkOverflow();
// ... and retry
}
}
}
/**
* Return a popped task, or null if DEQ is empty.
* Called ONLY by current thread.
* while(!w.isDone()) taskYield();
**/
protected final void taskJoin(final FJTask w) {
while (!w.isDone()) {
FJTask task = pop();
if (task != null) {
if (!task.isDone()) {
if (COLLECT_STATS) ++runs;
task.run();
task.setDone();
if (task == w) return; // fast exit if we just ran w
}
}
else
scan(w);
}
}
/**
* A specialized expansion of
* w.fork(); invoke(v); w.join();
**/
protected final void coInvoke(final FJTask w, final FJTask v) {
// inline push
int t = top;
if (t < (base & (deq.length-1)) + deq.length) {
deq[t & (deq.length-1)].put(w);
top = t + 1;
// inline invoke
if (!v.isDone()) {
if (COLLECT_STATS) ++runs;
v.run();
v.setDone();
}
// inline taskJoin
while (!w.isDone()) {
FJTask task = pop();
if (task != null) {
if (!task.isDone()) {
if (COLLECT_STATS) ++runs;
task.run();
task.setDone();
if (task == w) return; // fast exit if we just ran w
}
}
else
scan(w);
}
}
else // handle non-inlinable cases
slowCoInvoke(w, v);
}
/**
* Backup to handle noninlinable cases of coInvoke
**/
protected void slowCoInvoke(final FJTask w, final FJTask v) {
push(w); // let push deal with overflow
FJTask.invoke(v);
taskJoin(w);
}
/**
* Array-based version of coInvoke
**/
protected final void coInvoke(FJTask[] tasks) {
int nforks = tasks.length - 1;
// inline bulk push of all but one task
int t = top;
if (nforks >= 0 && t + nforks < (base & (deq.length-1)) + deq.length) {
for (int i = 0; i < nforks; ++i) {
deq[t++ & (deq.length-1)].put(tasks[i]);
top = t;
}
// inline invoke of one task
FJTask v = tasks[nforks];
if (!v.isDone()) {
if (COLLECT_STATS) ++runs;
v.run();
v.setDone();
}
// inline taskJoins
for (int i = 0; i < nforks; ++i) {
FJTask w = tasks[i];
while (!w.isDone()) {
FJTask task = pop();
if (task != null) {
if (!task.isDone()) {
if (COLLECT_STATS) ++runs;
task.run();
task.setDone();
}
}
else
scan(w);
}
}
}
else // handle non-inlinable cases
slowCoInvoke(tasks);
}
/**
* Backup to handle atypical or noninlinable cases of coInvoke
**/
protected void slowCoInvoke(FJTask[] tasks) {
for (int i = 0; i < tasks.length; ++i) push(tasks[i]);
for (int i = 0; i < tasks.length; ++i) taskJoin(tasks[i]);
}
}
concurrent-dfsg-1.3.4/ThreadFactory.java 0000644 0001750 0001750 00000001771 10202157355 020454 0 ustar wbaer wbaer 0000000 0000000 /*
File: ThreadFactory.java
Originally written by Doug Lea and released into the public domain.
This may be used for any purposes whatsoever without acknowledgment.
Thanks for the assistance and support of Sun Microsystems Labs,
and everyone contributing, testing, and using this code.
History:
Date Who What
30Jun1998 dl Create public version
*/
package EDU.oswego.cs.dl.util.concurrent;
/**
* Interface describing any class that can generate
* new Thread objects. Using ThreadFactories removes
* hardwiring of calls to new Thread
, enabling
* applications to use special thread subclasses, default
* prioritization settings, etc.
*
* class Producer implements Runnable {
* final Puttable chan;
* Producer(Puttable channel) { chan = channel; }
* public void run() {
* try {
* for(;;) { chan.put(produce()); }
* }
* catch (InterruptedException ex) {}
* }
* Object produce() { ... }
* }
*
*
* class Consumer implements Runnable {
* final Takable chan;
* Consumer(Takable channel) { chan = channel; }
* public void run() {
* try {
* for(;;) { consume(chan.take()); }
* }
* catch (InterruptedException ex) {}
* }
* void consume(Object x) { ... }
* }
*
* class Setup {
* void main() {
* Channel chan = new SomeChannelImplementation();
* Producer p = new Producer(chan);
* Consumer c = new Consumer(chan);
* new Thread(p).start();
* new Thread(c).start();
* }
* }
*
*
* try {
* for (;;) {
* Object item = channel.poll(0);
* if (item != null)
* process(item);
* else
* break;
* }
* }
* catch(InterruptedException ex) { ... }
*
* peek
, which returns
* but does NOT remove the next item that can be taken (or null
* if there is no such item). The peek operation has a limited
* range of applicability, and must be used with care. Unless it
* is known that a given thread is the only possible consumer
* of a channel, and that no time-out-based offer
operations
* are ever invoked, there is no guarantee that the item returned
* by peek will be available for a subsequent take.
* peek
returns null.
* size()
method. This allows careful
* use, for example in queue length monitors, appropriate to the
* particular implementation constraints and properties.
*
* class EndOfStream {
* // Application-dependent field/methods
* }
*
* And to have producers put an instance of this class into
* the channel when they are done. The consumer side can then
* check this via
*
* Object x = aChannel.take();
* if (x instanceof EndOfStream)
* // special actions; perhaps terminate
* else
* // process normally
*
*
* Object backOffTake(Channel q) throws InterruptedException {
* long waitTime = 0;
* for (;;) {
* Object x = q.poll(0);
* if (x != null)
* return x;
* else {
* Thread.sleep(waitTime);
* waitTime = 3 * waitTime / 2 + 1;
* }
* }
*
*
* class Service {
* private final Channel channel = ... some Channel implementation;
*
* private void backgroundTask(int taskParam) { ... }
*
* public void action(final int arg) {
* Runnable command =
* new Runnable() {
* public void run() { backgroundTask(arg); }
* };
* try { channel.put(command) }
* catch (InterruptedException ex) {
* Thread.currentThread().interrupt(); // ignore but propagate
* }
* }
*
* public Service() {
* Runnable backgroundLoop =
* new Runnable() {
* public void run() {
* for (;;) {
* try {
* Runnable task = (Runnable)(channel.take());
* task.run();
* }
* catch (InterruptedException ex) { return; }
* }
* }
* };
* new Thread(backgroundLoop).start();
* }
* }
*
*
*