concurrent-dfsg-1.3.4/0000755000175000017500000000000010202637436015047 5ustar wbaerwbaer00000000000000concurrent-dfsg-1.3.4/taskDemo/0000755000175000017500000000000010202634623016611 5ustar wbaerwbaer00000000000000concurrent-dfsg-1.3.4/taskDemo/Microscope.java0000644000175000017500000007444310202157355021575 0ustar wbaerwbaer00000000000000 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 []"); return; } JFrame frame = new JFrame(); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) {System.exit(0);}}); Microscope t = new Microscope(); frame.setSize(new Dimension(400, 400)); frame.getContentPane().add(t); frame.setVisible(true); t.init(); } // representations: Board board = new Board(); // The current board representation synchronized Board getBoard() { return board; } synchronized void setBoard(Board b) { board = b; boardPanel.repaint(); } Player player = Player.Blue; // current player (BLUE, GREEN) synchronized Player getPlayer() { return player; } synchronized void setPlayer(Player p) { player = p; } final AutoMover auto; // The move finder. final User user; // Mover for user moves Mover mover = null; // the current Mover (always == auto or user or null) synchronized Mover getMover() { return mover; } synchronized void setMover(Mover m) { mover = m; } synchronized boolean isMoving() { return mover != null; } Vector history = new Vector(); // List of completed moves; boolean demoMode = true; synchronized boolean getDemoMode() { return demoMode; } synchronized void setDemoMode(boolean b) { demoMode = b; } synchronized boolean toggleDemoMode() { return demoMode = !demoMode; } final BoardPanel boardPanel = new BoardPanel(); JLabel scoreLabel = new JLabel("Score: 0 "); JButton autoButton = new JButton(" Start "); JButton undoButton = new JButton("Undo"); JButton modeButton = new JButton("Demo mode"); JSlider levelSlider = new JSlider(JSlider.VERTICAL, 2, 6, lookAheads); public Microscope() { auto = new AutoMover(this); user = new User(this); JPanel topPanel = new JPanel(); autoButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (!isMoving()) { startMover(auto); autoButton.setText("Cancel"); } else { stopMover(); if (getDemoMode()) autoButton.setText(" Start "); else autoButton.setText(" Find "); } }}); modeButton.addActionListener(new ActionListener() { public synchronized void actionPerformed(ActionEvent e) { toggleDemoMode(); updateStatus(); }}); undoButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { undo(); }}); levelSlider.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { setLevel(((JSlider)(e.getSource())).getValue()); }}); // Dimension labDim = new Dimension(40, 16); Dimension labDim = new Dimension(72, 24); scoreLabel.setMinimumSize(labDim); scoreLabel.setPreferredSize(labDim); topPanel.add(autoButton); topPanel.add(modeButton); topPanel.add(undoButton); topPanel.add(scoreLabel); add(topPanel); levelSlider.setLabelTable(levelSlider.createStandardLabels(1)); levelSlider.setPaintLabels(true); JPanel botPanel = new JPanel(); botPanel.add(boardPanel); JPanel sliderPanel = new JPanel(); sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.Y_AXIS)); sliderPanel.add(levelSlider); sliderPanel.add(new JLabel("Level")); botPanel.add(sliderPanel); add(botPanel); } void initializeBoard() { board.reset(); board.occupy(Player.Blue, 0, 0); board.occupy(Player.Blue, Board.RANKS-1, Board.RANKS-1); board.occupy(Player.Green, 0, Board.RANKS-1); board.occupy(Player.Green, Board.RANKS-1, 0); setPlayer(Player.Blue); boardPanel.repaint(); } public void init() { initializeBoard(); if (autostart) { try { Thread.sleep(1000); } catch(InterruptedException ex) { return; } startMover(auto); } } synchronized void setLevel(int l) { lookAheads = l; if (lookAheads <= 1) lookAheads = 2; } public int level () { return Microscope.lookAheads; } // process a move (called only from mover) public void move(Move m, Mover mvr) { if (mvr != mover || m == null || (mvr == user && !m.isLegal())) { setMover(null); if (mvr == auto && autostart) { auto.stats(); System.exit(0); } } else { m.commit(); setBoard(m.board()); setPlayer(m.player().opponent()); history.addElement(m); if (mvr == auto && getDemoMode() && !m.isPass()) { if (getBoard().gameOver()) { if (autostart) { auto.stats(); System.exit(0); } else setMover(null); } else auto.startTurn(new Board(getBoard()), getPlayer()); } else setMover(null); } } // start up a Mover void startMover(Mover m) { Mover mvr = getMover(); if (mvr == null) { setMover(m); m.startTurn(new Board(getBoard()), player); } } // stop current Mover void stopMover() { Mover mvr = getMover(); if (mvr != null) { setMover(null); mvr.cancel(); } } // handle Undo button synchronized void undo() { if (mover == null) { if (history.size() > 1) { history.removeElementAt(history.size()-1); Move m = (Move)(history.lastElement()); setPlayer(m.player().opponent()); setBoard(m.board()); } else if (history.size() == 1) { history.removeAllElements(); initializeBoard(); } } } // handle click on tile void userMove(int row, int col) { startMover(user); user.choose(row, col); } void updateStatus() { // normally called from board update Player p = getPlayer(); int s = getBoard().score(p); scoreLabel.setForeground(displayColor(p)); scoreLabel.setText("Score: " + s); if (getDemoMode()) modeButton.setText("Demo mode"); else { if (getPlayer().isBlue()) modeButton.setText("Blue turn"); else modeButton.setText("Green turn"); } if (!autostart) auto.stats(); } static final int CELL_SIZE = 40; // size of a tile/cell static final Color paleGreen = new Color(152, 251, 152); static final Color darkGreen = new Color(60, 179, 113); static final Color possibleMoveColor = Color.yellow; public static Color displayColor(Player pl) { if (pl.isBlue()) return Color.blue; else if (pl.isGreen()) return darkGreen; else return Color.white; } public static Color lightDisplayColor(Player pl) { if (pl.isBlue()) return Color.cyan; else if (pl.isGreen()) return paleGreen; else return Color.gray; } class BoardPanel extends Canvas implements MouseListener { BoardPanel() { setSize(new Dimension(Board.RANKS * CELL_SIZE + 5, Board.RANKS * CELL_SIZE + 5)); addMouseListener(BoardPanel.this); } public void paint(Graphics g) { Board b = getBoard(); Player p = getPlayer(); // the cells for (int row = 0; row < Board.RANKS; row++) { for (int col = 0; col < Board.RANKS; col++) { // Highlight selected tile and legal destinations if (user.placing()) { if (user.hasMovedFrom(row, col)) g.setColor(lightDisplayColor(p)); else if (user.canMoveTo(row, col)) g.setColor(possibleMoveColor); else g.setColor(displayColor(b.occupant(row, col))); } else g.setColor(displayColor(b.occupant(row, col))); // tiles are just filled rectangles g.fillRect(row * CELL_SIZE, col * CELL_SIZE, CELL_SIZE, CELL_SIZE); } } // the grid over the cells g.setColor(Color.black); for ( int i = 0; i <= Board.RANKS; i++) { g.drawLine(0, i * CELL_SIZE, Board.RANKS * CELL_SIZE, i * CELL_SIZE); g.drawLine(i * CELL_SIZE, 0, i * CELL_SIZE, Board.RANKS * CELL_SIZE); } updateStatus(); } public void mouseReleased(MouseEvent evt) { int x = evt.getX(); int y = evt.getY(); int row = x / CELL_SIZE; int col = y / CELL_SIZE; if (Board.inBounds(row, col)) { // cell selection userMove(row, col); repaint(); } } public void mouseClicked(MouseEvent e) {} public void mousePressed(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} } /** * Player is just a glorified enumeration **/ static final class Player { public static final int EMPTY = 0; public static final int BLUE = 1; public static final int GREEN = 2; public static final int ILLEGAL_PLAYER_VALUE = 3; public static final Player Empty = new Player(EMPTY); public static final Player Blue = new Player(BLUE); public static final Player Green = new Player(GREEN); public static final Player Illegal = new Player(ILLEGAL_PLAYER_VALUE); /* private */ int code_; public Player(int code) { code_ = code; } public Player(Player p) { code_ = p.code_; } public boolean same(Player p) { return code_ == p.code_; } public boolean isEmpty() { return code_ == EMPTY; } public boolean isBlue() { return code_ == BLUE; } public boolean isGreen() { return code_ == GREEN; } public boolean isLegal() { return code_ <= GREEN; } public Player opponent() { if (code_ == GREEN) return Blue; else if (code_ == BLUE) return Green; else return Illegal; } } /** * Board configurations are represented by bit vectors. * Since there are only 49 cells, the bits can be held in `longs', * one for each player. *

* 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.java0000644000175000017500000001725510202157355020351 0ustar wbaerwbaer00000000000000/* 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 <0-4>"); return; } switch (benchmark) { case 0: /* cilk demo defaults */ nx = 4096; ny = 512; nt = 100; leafmaxcol = 10; break; case 1: /* cilk short benchmark options */ nx = 512; ny = 512; nt = 1; leafmaxcol = 10; break; case 2: /* cilk standard benchmark options */ nx = 4096; ny = 512; nt = 40; leafmaxcol = 10; break; case 3: /* cilk long benchmark options */ nx = 4096; ny = 1024; nt = 100; leafmaxcol = 1; break; case 4: /* hood demo faults */ nx = 1024; ny = 512; nt = 100; leafmaxcol = 16; break; default: System.out.println("Usage: java Heat <0-4>"); return; } System.out.print("Parameters: "); System.out.print(" granularity = " + leafmaxcol); System.out.print(" rows = " + nx); System.out.print(" columns = " + ny); System.out.println(" steps = " + nt); oldm = new double[nx][ny]; newm = new double[nx][ny]; try { FJTaskRunnerGroup g = new FJTaskRunnerGroup(procs); FJTask main = new FJTask() { public void run() { for (int timestep = 0; timestep <= nt; timestep++) { FJTask.invoke(new Compute(0, nx, timestep)); } } }; g.invoke(main); g.stats(); } catch (InterruptedException ex) { return; } } // constants (at least for this demo) static final double xu = 0.0; static final double xo = 1.570796326794896558; static final double yu = 0.0; static final double yo = 1.570796326794896558; static final double tu = 0.0; static final double to = 0.0000001; static final double dx = (xo - xu) / (nx - 1); static final double dy = (yo - yu) / (ny - 1); static final double dt = (to - tu) / nt; static final double dtdxsq = dt / (dx * dx); static final double dtdysq = dt / (dy * dy); // the function being applied across the cells static final double f(double x, double y) { return Math.sin(x) * Math.sin(y); } // random starting values static final double randa(double x, double t) { return 0.0; } static final double randb(double x, double t) { return Math.exp(-2*t) * Math.sin(x); } static final double randc(double y, double t) { return 0.0; } static final double randd(double y, double t) { return Math.exp(-2*t) * Math.sin(y); } static final double solu(double x, double y, double t) { return Math.exp(-2*t) * Math.sin(x) * Math.sin(y); } static final class Compute extends FJTask { final int lb; final int ub; final int time; Compute(int lowerBound, int upperBound, int timestep) { lb = lowerBound; ub = upperBound; time = timestep; } public void run() { if (ub - lb > leafmaxcol) { int mid = (lb + ub) / 2; coInvoke(new Compute(lb, mid, time), new Compute(mid, ub, time)); } else if (time == 0) // if first pass, initialize cells init(); else if (time %2 != 0) // alternate new/old compstripe(newm, oldm); else compstripe(oldm, newm); } /** Update all cells **/ final void compstripe(double[][] newMat, double[][] oldMat) { // manually mangled to reduce array indexing final int llb = (lb == 0) ? 1 : lb; final int lub = (ub == nx) ? nx - 1 : ub; double[] west; double[] row = oldMat[llb-1]; double[] east = oldMat[llb]; for (int a = llb; a < lub; a++) { west = row; row = east; east = oldMat[a+1]; double prev; double cell = row[0]; double next = row[1]; double[] nv = newMat[a]; for (int b = 1; b < ny-1; b++) { prev = cell; cell = next; double twoc = 2 * cell; next = row[b+1]; nv[b] = cell + dtdysq * (prev - twoc + next) + dtdxsq * (east[b] - twoc + west[b]); } } edges(newMat, llb, lub, tu + time * dt); } // the original version from cilk final void origcompstripe(double[][] newMat, double[][] oldMat) { final int llb = (lb == 0) ? 1 : lb; final int lub = (ub == nx) ? nx - 1 : ub; for (int a = llb; a < lub; a++) { for (int b = 1; b < ny-1; b++) { double cell = oldMat[a][b]; double twoc = 2 * cell; newMat[a][b] = cell + dtdxsq * (oldMat[a+1][b] - twoc + oldMat[a-1][b]) + dtdysq * (oldMat[a][b+1] - twoc + oldMat[a][b-1]); } } edges(newMat, llb, lub, tu + time * dt); } /** Initialize all cells **/ final void init() { final int llb = (lb == 0) ? 1 : lb; final int lub = (ub == nx) ? nx - 1 : ub; for (int a = llb; a < lub; a++) { /* inner nodes */ double[] ov = oldm[a]; double x = xu + a * dx; double y = yu; for (int b = 1; b < ny-1; b++) { y += dy; ov[b] = f(x, y); } } edges(oldm, llb, lub, 0); } /** Fill in edges with boundary values **/ final void edges(double [][] m, int llb, int lub, double t) { for (int a = llb; a < lub; a++) { double[] v = m[a]; double x = xu + a * dx; v[0] = randa(x, t); v[ny-1] = randb(x, t); } if (lb == 0) { double[] v = m[0]; double y = yu; for (int b = 0; b < ny; b++) { y += dy; v[b] = randc(y, t); } } if (ub == nx) { double[] v = m[nx - 1]; double y = yu; for (int b = 0; b < ny; b++) { y += dy; v[b] = randd(y, t); } } } } } concurrent-dfsg-1.3.4/taskDemo/Jacobi.java0000644000175000017500000001314110202157355020645 0ustar wbaerwbaer00000000000000// Jacobi iteration on a mesh. Based loosely on a Filaments demo import EDU.oswego.cs.dl.util.concurrent.*; public class Jacobi { static final int DEFAULT_LEAFCELLS = 1024; /** * The maximum number of matrix cells * at which to stop recursing down and instead directly update. **/ static final double EPSILON = 0.001; // convergence criterion public static void main(String[] args) { try { int procs; int n; int steps; int granularity = DEFAULT_LEAFCELLS; try { procs = Integer.parseInt(args[0]); n = Integer.parseInt(args[1]); steps = Integer.parseInt(args[2]); if (args.length > 3) granularity = Integer.parseInt(args[3]); } catch (Exception e) { System.out.println("Usage: java Jacobi []"); return; } // allocate enough space for edges double[][] a = new double[n+2][n+2]; double[][] b = new double[n+2][n+2]; // Simple initialization for demo. Fill all edges with 1's. // (All interiors are already default-initialized to zero.) for (int k = 0; k < n+2; ++k) { a[k][0] = 1.0; a[k][n+1] = 1.0; a[0][k] = 1.0; a[n+1][k] = 1.0; b[k][0] = 1.0; b[k][n+1] = 1.0; b[0][k] = 1.0; b[n+1][k] = 1.0; } Driver driver = new Driver(a, b, 1, n, 1, n, steps, granularity); FJTaskRunnerGroup g = new FJTaskRunnerGroup(procs); g.invoke(driver); g.stats(); } catch (InterruptedException ex) {} } abstract static class MatrixTree extends FJTask { // maximum difference between old and new values volatile double maxDiff; } static class LeafNode extends MatrixTree { final double[][] A; // matrix to get old values from final double[][] B; // matrix to put new values into // indices of current submatrix final int loRow; final int hiRow; final int loCol; final int hiCol; int steps = 0; // track even/odd steps LeafNode(double[][] A, double[][] B, int loRow, int hiRow, int loCol, int hiCol) { this.A = A; this.B = B; this.loRow = loRow; this.hiRow = hiRow; this.loCol = loCol; this.hiCol = hiCol; } public synchronized void run() { boolean AtoB = (steps++ % 2) == 0; double[][] a = (AtoB)? A : B; double[][] b = (AtoB)? B : A; double md = 0.0; // local for computing max diff for (int i = loRow; i <= hiRow; ++i) { for (int j = loCol; j <= hiCol; ++j) { double v = 0.25 * (a[i-1][j] + a[i][j-1] + a[i+1][j] + a[i][j+1]); b[i][j] = v; double diff = v - a[i][j]; if (diff < 0) diff = -diff; if (diff > md) md = diff; } } maxDiff = md; } } static class FourNode extends MatrixTree { final MatrixTree[] quads; FourNode(MatrixTree q1, MatrixTree q2, MatrixTree q3, MatrixTree q4) { quads = new MatrixTree[] { q1, q2, q3, q4 }; } public void run() { coInvoke(quads); double md = quads[0].maxDiff; quads[0].reset(); double m = quads[1].maxDiff; quads[1].reset(); if (m > md) md = m; m = quads[2].maxDiff; quads[2].reset(); if (m > md) md = m; m = quads[3].maxDiff; quads[3].reset(); maxDiff = (m > md)? m : md; } } static class TwoNode extends MatrixTree { final MatrixTree q1; final MatrixTree q2; TwoNode(MatrixTree q1, MatrixTree q2) { this.q1 = q1; this.q2 = q2; } public void run() { FJTask.coInvoke(q1, q2); double m1 = q1.maxDiff; double m2 = q2.maxDiff; maxDiff = (m1 > m2)? m1: m2; q1.reset(); q2.reset(); } } static class Driver extends FJTask { final MatrixTree mat; final int steps; Driver(double[][] A, double[][] B, int firstRow, int lastRow, int firstCol, int lastCol, int steps, int leafCells) { this.steps = steps; mat = build(A, B, firstRow, lastRow, firstCol, lastCol, leafCells); } MatrixTree build(double[][] a, double[][] b, int lr, int hr, int lc, int hc, int gran) { int rows = (hr - lr + 1); int cols = (hc - lc + 1); int mr = (lr + hr) / 2; // midpoints int mc = (lc + hc) / 2; int hrows = (mr - lr + 1); int hcols = (mc - lc + 1); if (rows * cols <= gran) { return new LeafNode(a, b, lr, hr, lc, hc); } else if (hrows * hcols >= gran) { return new FourNode(build(a, b, lr, mr, lc, mc, gran), build(a, b, lr, mr, mc+1, hc, gran), build(a, b, mr+1, hr, lc, mc, gran), build(a, b, mr+1, hr, mc+1, hc, gran)); } else if (cols >= rows) { return new TwoNode(build(a, b, lr, hr, lc, mc, gran), build(a, b, lr, hr, mc+1, hc, gran)); } else { return new TwoNode(build(a, b, lr, mr, lc, hc, gran), build(a, b, mr+1, hr, lc, hc, gran)); } } public void run() { double md = 0.0; for (int i = 1; i <= steps; ++i) { invoke(mat); md = mat.maxDiff; if (md < EPSILON) { System.out.println("Converged after " + i + " steps"); return; } else mat.reset(); } System.out.println("max diff after " + steps + " steps = " + md); } } } concurrent-dfsg-1.3.4/taskDemo/MatrixMultiply.java0000644000175000017500000001432510202157355022467 0ustar wbaerwbaer00000000000000 import EDU.oswego.cs.dl.util.concurrent.*; /** * Divide and Conquer matrix multiply demo **/ public class MatrixMultiply { static final int DEFAULT_GRANULARITY = 16; /** The quadrant size at which to stop recursing down * and instead directly multiply the matrices. * Must be a power of two. Minimum value is 2. **/ static int granularity = DEFAULT_GRANULARITY; public static void main(String[] args) { final String usage = "Usage: java MatrixMultiply [] \n Size and granularity must be powers of two.\n For example, try java MatrixMultiply 2 512 16"; try { int procs; int n; try { procs = Integer.parseInt(args[0]); n = Integer.parseInt(args[1]); if (args.length > 2) granularity = Integer.parseInt(args[2]); } catch (Exception e) { System.out.println(usage); return; } if ( ((n & (n - 1)) != 0) || ((granularity & (granularity - 1)) != 0) || granularity < 2) { System.out.println(usage); return; } float[][] a = new float[n][n]; float[][] b = new float[n][n]; float[][] c = new float[n][n]; init(a, b, n); FJTaskRunnerGroup g = new FJTaskRunnerGroup(procs); g.invoke(new Multiplier(a, 0, 0, b, 0, 0, c, 0, 0, n)); g.stats(); // check(c, n); } catch (InterruptedException ex) {} } // To simplify checking, fill with all 1's. Answer should be all n's. static void init(float[][] a, float[][] b, int n) { for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { a[i][j] = 1.0F; b[i][j] = 1.0F; } } } static void check(float[][] c, int n) { for (int i = 0; i < n; i++ ) { for (int j = 0; j < n; j++ ) { if (c[i][j] != n) { throw new Error("Check Failed at [" + i +"]["+j+"]: " + c[i][j]); } } } } /** * Multiply matrices AxB by dividing into quadrants, using algorithm: *

   *      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.java0000644000175000017500000001075110202157355021404 0ustar wbaerwbaer00000000000000import 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 \n (for example 2 1 48 5)."); return; } System.out.println("Integrating from " + start + " to " + end + " exponent: " + exp); Function f = new SampleFunction(exp); FJTaskRunnerGroup group = new FJTaskRunnerGroup(procs); Integrator integrator = new Integrator(f, 0.001, group); double result = integrator.integral(start, end); System.out.println("Answer = " + result); group.stats(); } /* This is all set up as if it were part of a more serious framework, but is for now just a demo, with all classes declared as static within Integrate */ /** A function to be integrated **/ static interface Function { double compute(double x); } /** * Sample from filaments demo. * Computes (2*n-1)*(x^(2*n-1)) for all odd values **/ static class SampleFunction implements Function { final int n; SampleFunction(int n) { this.n = n; } public double compute(double x) { double power = x; double xsq = x * x; double val = power; double di = 1.0; for (int i = n - 1; i > 0; --i) { di += 2.0; power *= xsq; val += di * power; } return val; } } static class Integrator { final Function f; // The function to integrate final double errorTolerance; final FJTaskRunnerGroup group; Integrator(Function f, double errorTolerance, FJTaskRunnerGroup group) { this.f = f; this.errorTolerance = errorTolerance; this.group = group; } double integral(double lowerBound, double upperBound) { double f_lower = f.compute(lowerBound); double f_upper = f.compute(upperBound); double initialArea = 0.5 * (upperBound-lowerBound) * (f_upper + f_lower); Quad q = new Quad(lowerBound, upperBound, f_lower, f_upper, initialArea); try { group.invoke(q); return q.area; } catch(InterruptedException ex) { Thread.currentThread().interrupt(); throw new Error("Interrupted during computation"); } } /** * FJTask to recursively perform the quadrature. * Algorithm: * Compute the area from lower bound to the center point of interval, * and from the center point to the upper bound. If this * differs from the value from lower to upper by more than * the error tolerance, recurse on each half. **/ class Quad extends FJTask { final double left; // lower bound final double right; // upper bound final double f_left; // value of the function evaluated at left final double f_right; // value of the function evaluated at right // Area initialized with original estimate from left to right. // It is replaced with refined value. volatile double area; Quad(double left, double right, double f_left, double f_right, double area) { this.left = left; this.right = right; this.f_left = f_left; this.f_right = f_right; this.area = area; } public void run() { double center = 0.5 * (left + right); double f_center = f.compute(center); double leftArea = 0.5 * (center - left) * (f_left + f_center); double rightArea = 0.5 * (right - center) * (f_center + f_right); double sum = leftArea + rightArea; double diff = sum - area; if (diff < 0) diff = -diff; if (diff >= errorTolerance) { Quad q1 = new Quad(left, center, f_left, f_center, leftArea); Quad q2 = new Quad(center, right, f_center, f_right, rightArea); coInvoke(q1, q2); sum = q1.area + q2.area; } area = sum; } } } } concurrent-dfsg-1.3.4/taskDemo/BufferTasks.java0000644000175000017500000001017410202157355021700 0ustar wbaerwbaer00000000000000import EDU.oswego.cs.dl.util.concurrent.*; import java.util.*; public class BufferTasks extends FJTask { static int niters = 1024 * 64; static int[] pairs = {1, 2, 4, 8, 16, 32, 64}; static int[] sizes = { 1024, 64, 1 }; public static void main(String[] args) { try { int procs; try { procs = Integer.parseInt(args[0]); } catch (Exception e) { System.out.println("Usage: java BufferTasks "); return; } System.out.print("pairs:"); for (int p = 0; p < pairs.length; ++p) System.out.print("\t" + pairs[p]); System.out.print("\n"); FJTaskRunnerGroup g = new FJTaskRunnerGroup(procs); g.invoke(new BufferTasks()); } catch (InterruptedException ex) {} } public void run() { for (int s = 0; s < sizes.length; ++s) { System.out.println("cap: " + sizes[s]); for (int p = 0; p < pairs.length; ++p) { buffer = new Buffer(sizes[s]); int npairs = pairs[p]; int iters = niters / npairs; long startTime = System.currentTimeMillis(); setCallbackCount(npairs * 2); for (int k = 0; k < npairs; ++k) { new Producer(iters).fork(); new Consumer(iters).fork(); } while (!checkDone()) yield(); long now = System.currentTimeMillis(); long time = now - startTime; long tpi = (time * 1000) / (npairs * niters); System.out.print("\t" + tpi); } System.out.print("\n"); getFJTaskRunnerGroup().stats(); } } /** * Keep track of callbacks so that test driver knows when * to terminate **/ int callbackCount; synchronized void notifyDone() { --callbackCount; } synchronized void setCallbackCount(int c) { callbackCount = c; } synchronized boolean checkDone() { return callbackCount == 0; } /** The shared buffer **/ Buffer buffer; class Producer extends FJTask { final int iters; Producer(int n) { iters = n; } public void run() { for (int n = iters; n > 0; --n) { // If cannot continue, create a new task to // take our place, and start it. if (!buffer.offer(new Integer(n))) { // Doesn't matter what's put in yield(); new Producer(n).start(); return; } } notifyDone(); } } class Consumer extends FJTask { final int iters; Consumer(int n) { iters = n; } public void run() { for (int n = iters; n > 0; --n) { // If cannot continue, create a new task to // take our place, and start it. if (buffer.poll() == null) { yield(); new Consumer(n).start(); return; } } notifyDone(); } } static class Buffer { protected Object[] array_; // the elements protected int putPtr_ = 0; // circular indices protected int takePtr_ = 0; final NonBlockingSemaphore putPermits; final NonBlockingSemaphore takePermits; public Buffer(int capacity){ putPermits = new NonBlockingSemaphore(capacity); takePermits = new NonBlockingSemaphore(0); array_ = new Object[capacity]; } public boolean offer(Object x){ if (!putPermits.attempt()) return false; synchronized(this) { array_[putPtr_] = x; if (++putPtr_ == array_.length) putPtr_ = 0; } takePermits.release(); return true; } public Object poll() { if (!takePermits.attempt()) return null; Object x; synchronized(this) { x = array_[takePtr_]; array_[takePtr_] = null; if (++takePtr_ == array_.length) takePtr_ = 0; } putPermits.release(); return x; } } static class NonBlockingSemaphore { private long permits_; public NonBlockingSemaphore(long initialPermits) { permits_ = initialPermits; } public synchronized boolean attempt() { if (permits_ > 0) { --permits_; return true; } else return false; } public synchronized void release() { ++permits_; } } } concurrent-dfsg-1.3.4/taskDemo/SFib.java0000644000175000017500000000507210202157355020305 0ustar wbaerwbaer00000000000000import EDU.oswego.cs.dl.util.concurrent.*; import java.net.*; import java.io.*; /** * Recursive task-based version of Fibonacci. Computes: *
 * 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 []"); return; } FJTaskRunnerGroup group = new FJTaskRunnerGroup(procs); ServerSocket socket = new ServerSocket(1618); for (;;) { final Socket connection = socket.accept(); group.execute(new Handler(connection)); } } catch (Exception e) { e.printStackTrace(); } } static class Handler extends FJTask { final Socket s; Handler(Socket s) { this.s = s; } public void run() { try { DataInputStream i = new DataInputStream(s.getInputStream()); DataOutputStream o = new DataOutputStream(s.getOutputStream()); int n = i.readInt(); SFib f = new SFib(n); invoke(f); o.writeInt(f.getAnswer()); } catch (Exception e) { e.printStackTrace(); } } } // Initialized with argument; replaced with result volatile int number; SFib(int n) { number = n; } int getAnswer() { if (!isDone()) throw new Error("Not yet computed"); return number; } public void run() { int n = number; // Handle base cases: if (n <= 1) { // Do nothing: fib(0) = 0; fib(1) = 1 } // Use sequential code for small problems: else if (n <= sequentialThreshold) { number = seqFib(n); } // Otherwise use recursive parallel decomposition: else { // Construct subtasks: SFib f1 = new SFib(n - 1); SFib f2 = new SFib(n - 2); // Run them in parallel: coInvoke(f1, f2); // Combine results: number = f1.number + f2.number; // (We know numbers are ready, so directly access them.) } } // Sequential version for arguments less than threshold static int seqFib(int n) { if (n <= 1) return n; else return seqFib(n-1) + seqFib(n-2); } } concurrent-dfsg-1.3.4/taskDemo/demos.html0000644000175000017500000001565010202157355020617 0ustar wbaerwbaer00000000000000 Task framework demo programs

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

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:

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

Fib #threads number [sequential-threshold]
A fibonacci program similar to the one listed in the documentation for the Task class. Invoke with an number to compute the fibonacci number for. For example 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.

MatrixMultiply #threads matrix-size granularity
A parallel divide-and-conquer matrix multiplication. The matrix size must be a power of two. The granularity controls the matrix size under which it stops recursively generating parallel tasks and performs a sequential multiply. It must also be a power of two and be at least 2. Default if not given is 16.

Jacobi #threads matrix-size max-iterations granularity
Performs Jacobi iteration of a mesh of matrix-size for either max-iterations or until converged. For demonstration, it is just applied to a square matrix of side matrix-size with all zeroes in the interior and all ones along edges. Default granularity if not given is 256 cells. See also BarrierJacobi, a different implementation using cyclic barriers (but not Tasks). It takes the same parameters except there is no first #threads argument.

Heat #threads 0-4
A standard parallel processing benchmark program that simulates heat diffusion across a mesh. The argument between 0 and 4 just selects among sets of parameter settings that you can find more about by reading the code.

LU #threads matrix-size #runs
LU matrix decomposition of randomly filled matrix. The matrix size must be a power of two, and at least 16. A granularity constant of 16 is built-in as a compile-time final constant. The optional #runs parameter optionally repeats the compuation on a new matrix.

Integrate #threads low high e
Computes integrals using recursive Gaussian Quadrature. A sample function to integrate (the sum of (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.

MSort #threads input-size
Performs a parallel merge/quick sort of input-size random integers.

Microscope #threads
An adaptation of the Microscope game. It uses tasks in a parallel exhaustive best-move finder with an adjustable look-ahead level. (Warning: because of the large fan-out of moves in this game, levels greater than 4 are still very slow.) By default, it is in Demo mode, where it just plays against itself until one side wins. If a second argument is given, it is interpreted as the level to play at, upon which it starts automatically and exits automatically when the game is over.

NQueens #threads board-size
Finds a placement of N queens that do not attack each other for a given NxN board size (where the board size must be at least 4). Since there are multiple solutions, the outcome is nondeterminstic when more than one thread is used. Results and timings may vary across runs.

BufferTasks #threads
A demo showing that you can, but probably shouldn't, use Tasks for classic producer-consumer programs. It sets up varying number of producer and consumer tasks, each operating on selected buffer sizes. If any producer cannot put, or consumer cannot take, it creates a whole new task to take over where it left off, starts it, and terminates. While this process cannot infinitely livelock, it can come pretty close.

Doug Lea
Last modified: Tue Jan 18 07:12:03 EST 2000 concurrent-dfsg-1.3.4/taskDemo/FibVCB.java0000644000175000017500000000445210202157355020516 0ustar wbaerwbaer00000000000000import 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 []"); return; } FJTaskRunnerGroup g = new FJTaskRunnerGroup(procs); FibVCB f = new FibVCB(num, null); g.invoke(f); g.stats(); long result = f.getAnswer(); System.out.println("FibVCB: Size: " + num + " Answer: " + result); } catch (InterruptedException ex) {} } volatile int number = 0; final FibVCB parent; // callback target int callbacksExpected = 0; volatile int callbacksReceived = 0; FibVCB(int n, FibVCB p) { number = n; parent = p; } // Callback method called from subtasks upon completion synchronized void addResult(int n) { number += n; ++callbacksReceived; } synchronized int getAnswer() { if (!isDone()) throw new Error("Not yet computed"); return number; } public void run() { // same structure as join-based version int n = number; if (n <= 1) { // nothing } else if (n <= sequentialThreshold) { number = seqFib(n); } else { // clear number so subtasks can fill in number = 0; // establish number of callbacks expected callbacksExpected = 2; new FibVCB(n - 1, this).fork(); new FibVCB(n - 2, this).fork(); // Wait for callbacks from children while (callbacksReceived < callbacksExpected) yield(); } // Call back parent if (parent != null) parent.addResult(number); } // Sequential version for arguments less than threshold static int seqFib(int n) { if (n <= 1) return n; else return seqFib(n-1) + seqFib(n-2); } } concurrent-dfsg-1.3.4/taskDemo/SFibClient.java0000644000175000017500000000073110202157355021441 0ustar wbaerwbaer00000000000000 import java.net.*; import java.io.*; public class SFibClient { public static void main(String[] args) { try { Socket s = new Socket("gee.cs.oswego.edu", 1618); DataInputStream i = new DataInputStream(s.getInputStream()); DataOutputStream o = new DataOutputStream(s.getOutputStream()); o.writeInt(34); int answer = i.readInt(); System.out.println("Answer " + answer); } catch (Exception e) { e.printStackTrace(); } } } concurrent-dfsg-1.3.4/taskDemo/Fib.java0000644000175000017500000000403310202157355020156 0ustar wbaerwbaer00000000000000import EDU.oswego.cs.dl.util.concurrent.*; /** * Recursive task-based version of Fibonacci. Computes: *
 * 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 []"); return; } FJTaskRunnerGroup g = new FJTaskRunnerGroup(procs); Fib f = new Fib(num); g.invoke(f); g.stats(); long result = f.getAnswer(); System.out.println("Fib: Size: " + num + " Answer: " + result); } catch (InterruptedException ex) {} } // Initialized with argument; replaced with result volatile int number; Fib(int n) { number = n; } int getAnswer() { if (!isDone()) throw new Error("Not yet computed"); return number; } public void run() { int n = number; // Handle base cases: if (n <= 1) { // Do nothing: fib(0) = 0; fib(1) = 1 } // Use sequential code for small problems: else if (n <= sequentialThreshold) { number = seqFib(n); } // Otherwise use recursive parallel decomposition: else { // Construct subtasks: Fib f1 = new Fib(n - 1); Fib f2 = new Fib(n - 2); // Run them in parallel: coInvoke(f1, f2); // Combine results: number = f1.number + f2.number; // (We know numbers are ready, so directly access them.) } } // Sequential version for arguments less than threshold static int seqFib(int n) { if (n <= 1) return n; else return seqFib(n-1) + seqFib(n-2); } } concurrent-dfsg-1.3.4/taskDemo/MSort.java0000644000175000017500000001770210202157355020531 0ustar wbaerwbaer00000000000000import EDU.oswego.cs.dl.util.concurrent.*; import java.util.Random; /** * Sample sort program adapted from a demo in * Cilk and * Hood. * **/ class MSort { public static void main (String[] args) { try { int n = 262144; int p = 2; try { p = Integer.parseInt(args[0]); n = Integer.parseInt(args[1]); } catch (Exception e) { System.out.println("Usage: java MSort "); return; } int[] A = new int[n]; // Fill in array A with random values. Random rng = new Random(); for (int i = 0; i < n; i++) A[i] = rng.nextInt(); int[] workSpace = new int[n]; FJTaskRunnerGroup g = new FJTaskRunnerGroup(p); Sorter t = new Sorter(A, 0, workSpace, 0, n); g.invoke(t); g.stats(); // checkSorted(A, n); } catch (InterruptedException ex) {} } static void checkSorted (int[] A, int n) { for (int i = 0; i < n - 1; i++) { if (A[i] > A[i+1]) { throw new Error("Unsorted at " + i + ": " + A[i] + " / " + A[i+1]); } } } /* Threshold values */ // Cutoff for when to do sequential versus parallel merges static final int MERGE_SIZE = 2048; // Cutoff for when to do sequential quicksort versus parallel mergesort static final int QUICK_SIZE = 2048; // Cutoff for when to use insertion-sort instead of quicksort static final int INSERTION_SIZE = 20; static class Sorter extends FJTask { final int[] A; // Input array. final int aLo; // offset into the part of array we deal with final int[] W; // workspace for merge final int wLo; final int n; // Number of elements in (sub)arrays. Sorter (int[] A, int aLo, int[] W, int wLo, int n) { this.A = A; this.aLo = aLo; this.W = W; this.wLo = wLo; this.n = n; } public void run() { /* Algorithm: IF array size is small, just use a sequential quicksort Otherwise: Break array in half. For each half, break the half in half (i.e., quarters), sort the quarters merge them together Finally, merge together the two halves. */ if (n <= QUICK_SIZE) { qs(); } else { int q = n/4; coInvoke(new Seq(new Par(new Sorter(A, aLo, W, wLo, q), new Sorter(A, aLo+q, W, wLo+q, q) ), new Merger(A, aLo, q, A, aLo+q, q, W, wLo) ), new Seq(new Par(new Sorter(A, aLo+q*2, W, wLo+q*2, q), new Sorter(A, aLo+q*3, W, wLo+q*3, n-q*3) ), new Merger(A, aLo+q*2, q, A, aLo+q*3, n-q*3, W, wLo+q*2) ) ); invoke(new Merger(W, wLo, q*2, W, wLo+q*2, n-q*2, A, aLo)); } } /** Relay to quicksort within sync method to ensure memory barriers **/ synchronized void qs() { quickSort(aLo, aLo+n-1); } /** A standard sequential quicksort **/ void quickSort(int lo, int hi) { // If under threshold, use insertion sort if (hi-lo+1l <= INSERTION_SIZE) { for (int i = lo + 1; i <= hi; i++) { int t = A[i]; int j = i - 1; while (j >= lo && A[j] > t) { A[j+1] = A[j]; --j; } A[j+1] = t; } return; } // Use median-of-three(lo, mid, hi) to pick a partition. // Also swap them into relative order while we are at it. int mid = (lo + hi) / 2; if (A[lo] > A[mid]) { int t = A[lo]; A[lo] = A[mid]; A[mid] = t; } if (A[mid]> A[hi]) { int t = A[mid]; A[mid] = A[hi]; A[hi] = t; if (A[lo]> A[mid]) { t = A[lo]; A[lo] = A[mid]; A[mid] = t; } } int left = lo+1; // start one past lo since already handled lo int right = hi-1; // similarly int partition = A[mid]; for (;;) { while (A[right] > partition) --right; while (left < right && A[left] <= partition) ++left; if (left < right) { int t = A[left]; A[left] = A[right]; A[right] = t; --right; } else break; } quickSort(lo, left); quickSort(left+1, hi); } } static class Merger extends FJTask { final int[] A; // First sorted array. final int aLo; // first index of A final int aSize; // number of elements final int[] B; // Second sorted array. final int bLo; final int bSize; final int[] out; // Output array. final int outLo; Merger (int[] A, int aLo, int aSize, int[] B, int bLo, int bSize, int[] out, int outLo) { this.out = out; this.outLo = outLo; // A must be largest of the two for split. Might as well swap now. if (aSize >= bSize) { this.A = A; this.aLo = aLo; this.aSize = aSize; this.B = B; this.bLo = bLo; this.bSize = bSize; } else { this.A = B; this.aLo = bLo; this.aSize = bSize; this.B = A; this.bLo = aLo; this.bSize = aSize; } } public void run() { /* Algorithm: If the arrays are small, then just sequentially merge. Otherwise: Split A in half. Find the greatest point in B less than the beginning of the second half of A. In parallel: merge the left half of A with elements of B up to split point merge the right half of A with elements of B past split point */ if (aSize <= MERGE_SIZE) { merge(); } else { int aHalf = aSize / 2; int bSplit = findSplit(A[aLo + aHalf]); coInvoke(new Merger(A, aLo, aHalf, B, bLo, bSplit, out, outLo), new Merger(A, aLo+aHalf, aSize-aHalf, B, bLo+bSplit, bSize-bSplit, out, outLo+aHalf+bSplit)); } } /** find greatest point in B less than value. return 0-based offset **/ synchronized int findSplit(int value) { int low = 0; int high = bSize; while (low < high) { int middle = low + (high - low) / 2; if (value <= B[bLo+middle]) high = middle; else low = middle + 1; } return high; } /** A standard sequential merge **/ synchronized void merge() { int a = aLo; int aFence = aLo+aSize; int b = bLo; int bFence = bLo+bSize; int k = outLo; while (a < aFence && b < bFence) { if (A[a] < B[b]) out[k++] = A[a++]; else out[k++] = B[b++]; } while (a < aFence) out[k++] = A[a++]; while (b < bFence) out[k++] = B[b++]; } } } concurrent-dfsg-1.3.4/taskDemo/NQueens.java0000644000175000017500000000521310202157355021035 0ustar wbaerwbaer00000000000000// Adapted from a cilk demo import EDU.oswego.cs.dl.util.concurrent.*; class NQueens extends FJTask { static int boardSize; public static void main(String[] args) { try { int procs; try { procs = Integer.parseInt(args[0]); boardSize = Integer.parseInt(args[1]); } catch (Exception e) { System.out.println("Usage: java NQueens "); return; } if (boardSize <= 3) { System.out.println("There is no solution for board size <= 3"); return; } FJTaskRunnerGroup g = new FJTaskRunnerGroup(procs); NQueens f = new NQueens(new int[0]); g.execute(f); int[] board = result.await(); g.stats(); System.out.print("Result:"); for (int i = 0; i < board.length; ++i) { System.out.print(" " + board[i]); } System.out.println(); } catch (InterruptedException ex) {} } /** * Global variable holding the result of search. * FJTasks check this to see if it is nonnull, * if so, returning early because a result has been found. * In a more serious program, we might use a fancier scheme * to reduce read/write pressure on this variable. **/ static final class Result { private int[] board = null; synchronized int[] get() { return board; } synchronized void set(int[] b) { if (board == null) { board = b; notifyAll(); } } synchronized int[] await() throws InterruptedException { while (board == null) { wait(); } return board; } } static final Result result = new Result(); // Boards are represented as arrays where each cell // holds the column number of the queen in that row final int[] sofar; NQueens(int[] a) { this.sofar = a; } public void run() { if (result.get() == null) { // check if already solved int row = sofar.length; if (row >= boardSize) // done result.set(sofar); else { for (int q = 0; q < boardSize; ++q) { // Check if can place queen in column q of next row boolean attacked = false; for (int i = 0; i < row; i++) { int p = sofar[i]; if (q == p || q == p - (row - i) || q == p + (row - i)) { attacked = true; break; } } // Fork to explore moves from new configuration if (!attacked) { int[] next = new int[row+1]; for (int k = 0; k < row; ++k) next[k] = sofar[k]; next[row] = q; new NQueens(next).fork(); } } } } } } concurrent-dfsg-1.3.4/taskDemo/LU.java0000644000175000017500000002203710202157355020002 0ustar wbaerwbaer00000000000000 import EDU.oswego.cs.dl.util.concurrent.*; /** * LU matrix decomposition demo * Based on those in Cilk and Hood **/ public class LU { // granularity is hard-wired as compile-time constant here static final int BLOCK_SIZE = 16; static final boolean CHECK = false; // set true to check answer public static void main(String[] args) { final String usage = "Usage: java LU [runs] \n For example, try java LU 2 512"; try { int procs; int n; int runs = 1; try { procs = Integer.parseInt(args[0]); n = Integer.parseInt(args[1]); if (args.length > 2) runs = Integer.parseInt(args[2]); } catch (Exception e) { System.out.println(usage); return; } if ( ((n & (n - 1)) != 0)) { System.out.println(usage); return; } for (int run = 0; run < runs; ++run) { double[][] m = new double[n][n]; randomInit(m, n); double[][] copy = null; if (CHECK) { copy = new double[n][n]; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { copy[i][j] = m[i][j]; } } } Block M = new Block(m, 0, 0); FJTaskRunnerGroup g = new FJTaskRunnerGroup(procs); g.invoke(new LowerUpper(n, M)); g.stats(); g.interruptAll(); if (CHECK) check(m, copy, n); } } catch (InterruptedException ex) {} } static void randomInit(double[][] M, int n) { java.util.Random rng = new java.util.Random(); for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) M[i][j] = rng.nextDouble(); // for compatibility with hood demo, force larger diagonals for (int k = 0; k < n; ++k) M[k][k] *= 10.0; } static void check(double[][] LU, double[][] M, int n) { double maxDiff = 0.0; // track max difference for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { double v = 0.0; int k; for (k = 0; k < i && k <= j; k++ ) v += LU[i][k] * LU[k][j]; if (k == i && k <= j ) v += LU[k][j]; double diff = M[i][j] - v; if (diff < 0) diff = -diff; if (diff > 0.001) { System.out.println("large diff at[" + i + "," + j + "]: " + M[i][j] + " vs " + v); } if (diff > maxDiff) maxDiff = diff; } } System.out.println("Max difference = " + maxDiff); } // Blocks record underlying matrix, and offsets into current block static class Block { final double[][] m; final int loRow; final int loCol; Block(double[][] mat, int lr, int lc) { m = mat; loRow = lr; loCol = lc; } } static class Schur extends FJTask { final int size; final Block V; final Block W; final Block M; Schur(int size, Block V, Block W, Block M) { this.size = size; this.V = V; this.W = W; this.M = M; } void schur() { // base case for (int j = 0; j < BLOCK_SIZE; ++j) { for (int i = 0; i < BLOCK_SIZE; ++i) { double s = M.m[i+M.loRow][j+M.loCol]; for (int k = 0; k < BLOCK_SIZE; ++k) { s -= V.m[i+V.loRow][k+V.loCol] * W.m[k+W.loRow][j+W.loCol]; } M.m[i+M.loRow][j+M.loCol] = s; } } } public void run() { if (size == BLOCK_SIZE) { schur(); } else { int h = size / 2; Block M00 = new Block(M.m, M.loRow, M.loCol); Block M01 = new Block(M.m, M.loRow, M.loCol+h); Block M10 = new Block(M.m, M.loRow+h, M.loCol); Block M11 = new Block(M.m, M.loRow+h, M.loCol+h); Block V00 = new Block(V.m, V.loRow, V.loCol); Block V01 = new Block(V.m, V.loRow, V.loCol+h); Block V10 = new Block(V.m, V.loRow+h, V.loCol); Block V11 = new Block(V.m, V.loRow+h, V.loCol+h); Block W00 = new Block(W.m, W.loRow, W.loCol); Block W01 = new Block(W.m, W.loRow, W.loCol+h); Block W10 = new Block(W.m, W.loRow+h, W.loCol); Block W11 = new Block(W.m, W.loRow+h, W.loCol+h); coInvoke(new FJTask[] { seq(new Schur(h, V00, W00, M00), new Schur(h, V01, W10, M00)), seq(new Schur(h, V00, W01, M01), new Schur(h, V01, W11, M01)), seq(new Schur(h, V10, W00, M10), new Schur(h, V11, W10, M10)), seq(new Schur(h, V10, W01, M11), new Schur(h, V11, W11, M11)) }); } } } static class Lower extends FJTask { final int size; final Block L; final Block M; Lower(int size, Block L, Block M) { this.size = size; this.L = L; this.M = M; } void lower() { // base case for (int i = 1; i < BLOCK_SIZE; ++i) { for (int k = 0; k < i; ++k) { double a = L.m[i+L.loRow][k+L.loCol]; double[] x = M.m[k+M.loRow]; double[] y = M.m[i+M.loRow]; int n = BLOCK_SIZE; for (int p = n-1; p >= 0; --p) { y[p+M.loCol] -= a * x[p+M.loCol]; } } } } public void run() { if (size == BLOCK_SIZE) { lower(); } else { int h = size / 2; Block M00 = new Block(M.m, M.loRow, M.loCol); Block M01 = new Block(M.m, M.loRow, M.loCol+h); Block M10 = new Block(M.m, M.loRow+h, M.loCol); Block M11 = new Block(M.m, M.loRow+h, M.loCol+h); Block L00 = new Block(L.m, L.loRow, L.loCol); Block L01 = new Block(L.m, L.loRow, L.loCol+h); Block L10 = new Block(L.m, L.loRow+h, L.loCol); Block L11 = new Block(L.m, L.loRow+h, L.loCol+h); coInvoke( new Seq(new FJTask[] { new Lower(h, L00, M00), new Schur(h, L10, M00, M10), new Lower(h, L11, M10) }), new Seq(new FJTask[] { new Lower(h, L00, M01), new Schur(h, L10, M01, M11), new Lower(h, L11, M11) }) ); } } } static class Upper extends FJTask { final int size; final Block U; final Block M; Upper(int size, Block U, Block M) { this.size = size; this.U = U; this.M = M; } void upper() { // base case for (int i = 0; i < BLOCK_SIZE; ++i) { for (int k = 0; k < BLOCK_SIZE; ++k) { double a = M.m[i+M.loRow][k+M.loCol] / U.m[k+U.loRow][k+U.loCol]; M.m[i+M.loRow][k+M.loCol] = a; double[] x = U.m[k+U.loRow]; double[] y = M.m[i+M.loRow]; int n = BLOCK_SIZE - k - 1; for (int p = n - 1; p >= 0; --p) { y[p+k+1+M.loCol] -= a * x[p+k+1+U.loCol]; } } } } public void run() { if (size == BLOCK_SIZE) { upper(); } else { int h = size / 2; Block M00 = new Block(M.m, M.loRow, M.loCol); Block M01 = new Block(M.m, M.loRow, M.loCol+h); Block M10 = new Block(M.m, M.loRow+h, M.loCol); Block M11 = new Block(M.m, M.loRow+h, M.loCol+h); Block U00 = new Block(U.m, U.loRow, U.loCol); Block U01 = new Block(U.m, U.loRow, U.loCol+h); Block U10 = new Block(U.m, U.loRow+h, U.loCol); Block U11 = new Block(U.m, U.loRow+h, U.loCol+h); coInvoke( new Seq(new FJTask[] { new Upper(h, U00, M00), new Schur(h, M00, U01, M01), new Upper(h, U11, M01) }), new Seq(new FJTask[] { new Upper(h, U00, M10), new Schur(h, M10, U01, M11), new Upper(h, U11, M11) }) ); } } } static class LowerUpper extends FJTask { final int size; final Block M; LowerUpper(int size, Block M) { this.size = size; this.M = M; } void lu() { // base case for (int k = 0; k < BLOCK_SIZE; ++k) { for (int i = k+1; i < BLOCK_SIZE; ++i) { double b = M.m[k+M.loRow][k+M.loCol]; double a = M.m[i+M.loRow][k+M.loCol] / b; M.m[i+M.loRow][k+M.loCol] = a; double[] x = M.m[k+M.loRow]; double[] y = M.m[i+M.loRow]; int n = BLOCK_SIZE-k-1; for (int p = n-1; p >= 0; --p) { y[k+1+p+M.loCol] -= a * x[k+1+p+M.loCol]; } } } } public void run() { if (size == BLOCK_SIZE) { lu(); } else { int h = size / 2; Block M00 = new Block(M.m, M.loRow, M.loCol); Block M01 = new Block(M.m, M.loRow, M.loCol+h); Block M10 = new Block(M.m, M.loRow+h, M.loCol); Block M11 = new Block(M.m, M.loRow+h, M.loCol+h); invoke(new LowerUpper(h, M00)); coInvoke(new Lower(h, M00, M01), new Upper(h, M00, M10)); invoke(new Schur(h, M10, M01, M11)); invoke(new LowerUpper(h, M11)); } } } } concurrent-dfsg-1.3.4/taskDemo/BarrierJacobi.java0000644000175000017500000001277010202157355022163 0ustar wbaerwbaer00000000000000// Barrier version of Jacobi iteration import EDU.oswego.cs.dl.util.concurrent.*; public class BarrierJacobi { static final int DEFAULT_GRANULARITY = 128; /** * The maximum submatrix length (both row-wise and column-wise) * for any Segment **/ static int granularity = DEFAULT_GRANULARITY; static final double EPSILON = 0.001; // convergence criterion public static void main(String[] args) { try { int n; int steps; try { n = Integer.parseInt(args[0]); steps = Integer.parseInt(args[1]); if (args.length > 2) granularity = Integer.parseInt(args[2]); } catch (Exception e) { System.out.println("Usage: java BarrierJacobi []"); return; } // allocate enough space for edges double[][] a = new double[n+2][n+2]; double[][] b = new double[n+2][n+2]; // Simple initialization for demo. Fill all edges with 1's. // (All interiors are already default-initialized to zero.) for (int k = 0; k < n+2; ++k) { a[k][0] = 1.0; a[k][n+1] = 1.0; a[0][k] = 1.0; a[n+1][k] = 1.0; b[k][0] = 1.0; b[k][n+1] = 1.0; b[0][k] = 1.0; b[n+1][k] = 1.0; } long startTime = System.currentTimeMillis(); new Driver(a, b, 1, n, 1, n, steps).compute(); long time = System.currentTimeMillis() - startTime; double secs = ((double)time) / 1000.0; System.out.println("Compute Time: " + secs); } catch (InterruptedException ex) {} } static class Segment implements Runnable { double[][] A; // matrix to get old values from double[][] B; // matrix to put new values into // indices of current submatrix final int loRow; final int hiRow; final int loCol; final int hiCol; final int steps; final CyclicBarrier barrier; final Segment[] allSegments; volatile double maxDiff; // maximum difference between old and new values volatile boolean converged = false; Segment(double[][] A, double[][] B, int loRow, int hiRow, int loCol, int hiCol, int steps, CyclicBarrier barrier, Segment[] allSegments) { this.A = A; this.B = B; this.loRow = loRow; this.hiRow = hiRow; this.loCol = loCol; this.hiCol = hiCol; this.steps = steps; this.barrier = barrier; this.allSegments = allSegments; } void convergenceCheck(int step) { for (int i = 0; i < allSegments.length; ++i) if (allSegments[i].maxDiff > EPSILON) return; System.out.println("Converged after " + step + " steps"); for (int i = 0; i < allSegments.length; ++i) allSegments[i].converged = true; } public void run() { try { double[][] a = A; double[][] b = B; for (int i = 1; i <= steps && !converged; ++i) { maxDiff = update(a, b); int index = barrier.barrier(); if (index == 0) convergenceCheck(i); barrier.barrier(); double[][] tmp = a; a = b; b = tmp; } } catch(Exception ex) { return; } } double update(double[][] a, double[][] b) { double md = 0.0; // local for computing max diff for (int i = loRow; i <= hiRow; ++i) { for (int j = loCol; j <= hiCol; ++j) { double v = 0.25 * (a[i-1][j] + a[i][j-1] + a[i+1][j] + a[i][j+1]); b[i][j] = v; double diff = v - a[i][j]; if (diff < 0) diff = -diff; if (diff > md) md = diff; } } return md; } } static class Driver { double[][] A; // matrix to get old values from double[][] B; // matrix to put new values into final int loRow; // indices of current submatrix final int hiRow; final int loCol; final int hiCol; final int steps; Driver(double[][] mat1, double[][] mat2, int firstRow, int lastRow, int firstCol, int lastCol, int steps) { this.A = mat1; this.B = mat2; this.loRow = firstRow; this.hiRow = lastRow; this.loCol = firstCol; this.hiCol = lastCol; this.steps = steps; } public void compute() throws InterruptedException { int rows = hiRow - loRow + 1; int cols = hiCol - loCol + 1; int rblocks = rows / granularity; int cblocks = cols / granularity; int n = rblocks * cblocks; System.out.println("Using " + n + " segments (threads)"); Segment[] segs = new Segment[n]; Thread[] threads = new Thread[n]; CyclicBarrier barrier = new CyclicBarrier(n); int k = 0; for (int i = 0; i < rblocks; ++i) { int lr = loRow + i * granularity; int hr = lr + granularity; if (i == rblocks-1) hr = hiRow; for (int j = 0; j < cblocks; ++j) { int lc = loCol + j * granularity; int hc = lc + granularity; if (j == cblocks-1) hc = hiCol; segs[k] = new Segment(A, B, lr, hr, lc, hc, steps, barrier, segs); threads[k] = new Thread(segs[k]); ++k; } } for (k = 0; k < n; ++k) threads[k].start(); for (k = 0; k < n; ++k) threads[k].join(); double maxd = 0; for (k = 0; k < n; ++k) { double md = segs[k].maxDiff; if (md > maxd) maxd = md; } System.out.println("Max diff after " + steps + " steps = " + maxd); } } } concurrent-dfsg-1.3.4/misc/0000755000175000017500000000000010202634623015775 5ustar wbaerwbaer00000000000000concurrent-dfsg-1.3.4/misc/SwingWorker.java0000644000175000017500000002245510202157355021133 0ustar wbaerwbaer00000000000000/* File: SwingWorker.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 for util.concurrent by Joseph Bowbeer. */ package EDU.oswego.cs.dl.util.concurrent.misc; import java.lang.reflect.InvocationTargetException; import javax.swing.SwingUtilities; import EDU.oswego.cs.dl.util.concurrent.*; /** * An abstract class that you subclass to perform GUI-related work * in a dedicated thread. *

* 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 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. *

* Sample Usage

*

 * 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 * *

[ 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 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.java0000644000175000017500000000161010202157355020225 0ustar wbaerwbaer00000000000000package 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.java0000644000175000017500000000475110202157355020313 0ustar wbaerwbaer00000000000000 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.java0000644000175000017500000001320310202157355020406 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000602510202157355021177 0ustar wbaerwbaer00000000000000 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. *

* 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.java0000644000175000017500000017735210202157355023063 0ustar wbaerwbaer00000000000000/* 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: *

    *
  1. javac -d base of some CLASSPATH *.java
    * You'll need Swing (JFC). (This * program currently imports the javax.swing versions. * You can edit imports to instead use other versions.) *
  2. java EDU.oswego.cs.dl.util.concurrent.misc.SynchronizationTimer
    *
  3. Click start. * Clicking stop cancels the run. Cancellation can take * a while when there are a lot of threads. *
  4. For more explanation about tested classes, see * Documentation for util.concurrent *
* *

* Synchronization schemes are tested around implementations and * subclasses of 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. * *

* 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 perfmeter or top on unix) * alongside this program * to find out. *

* 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.) *

* *
Number of threads * *
Controls concurrency. The indicated number of threads are * started simultaneously and then waited out. * *
Contention. * *
Percent sharing among threads. Zero percent means that each * thread has its own RNG object, so there is no * interference among threads. The zero * percent case thus shows the cost of synchronization mechanics that * happen to never be needed. * 100 percent sharing means that all * threads call methods on the same object, so each thread will have to * wait until the RNG objects are not being used by others. * In between is in between: Only the given percentage of calls are * made to shared RNG objects; others are to unshared. * Contention in classes that use Channels works slightly differently: * The Channels are shared, not the base RNG objects. (Another way * of looking at it is that tests demonstrate effects of multiple * producers and consumers on the same channel.) * *
Classes *
You can choose to only test the indicated classes. You can * probably figure out how to add more classes to run yourself. * *
Calls per thread per test * *
Specifies number of iterations per thread per test. The listed * times are averages over these iterations. The default seems to * provide precise enough values for informal testing purposes. * You should expect to see a fair amount of variation across * repeated runs. * If you get zeroes printed in any cell, this means that the * test ran too fast to measure in milleconds, so you should increase the * iterations value. * *
Computations per call * *
Specifies length of each call by setting an internal looping * parameter inside each RNG object. Shorter calls lead to shorter * times between synchronization measures. Longer calls, along with * high contention can be used to force timeouts to occur. * *
Iterations per barrier. * *
Specifies the number of iterations performed by each thread until * a synchronization barrier is forced with other threads, forcing * it to wait for other threads to reach the same number of iterations. This * controls the amount of interaction (versus contention) among threads. * Setting to a value greater than the number of iterations per test * effectively disables barriers. * *
Threads per barrier * *
Specifies how many threads are forced to synchronize at each * barrier point. Greater numbers cause more threads to wait for each * other at barriers. Setting to 1 means that a thread only has to * wait for itself, which means not to wait at all. * *
Lock mode * *
For classes that support it, this controls whether mutual * exclusion waits are done via standard blocking synchronization, or * a loop repeatedly calling a timed wait. * *
Producer mode * *
For classes that support it, this controls whether producers * perform blocking puts versus loops repeatedly calling offer. * *
Consumer mode * *
For classes that support it, this controls whether consumers * perform blocking takes versus loops repeatedly calling poll. * *
Timeouts * *
Specifies the duration of timeouts used in timeout mode. A * value of zero results in pure spin-loops. * *
Producer/consumer rates. * *
For tests involving producer/consumer pairs, this controls * whether the producer is much faster, about the same speed, or much * slower than the consumer. This is implemented by having the * producer do all, half, or none of the actual calls to update, in * addition to adding elements to channel. * *
Buffer capacity * *
For tests involving finite capacity * buffers, this controls maximum buffer size. * *
* *

* 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: * *

* * *
Using built-in synchronization *
Versions of RNG classes that use (or don't use) * synchronized methods and/or blocks. Also some tests of * simple SynchronizedVariables. Tests that would not * be thread-safe are not run when there is more than one * thread and non-zero contention. * * *
Using Sync classes as locks *
Classes protecting public methods via Semaphores, mutexes, etc. * In each case, the outer public methods delegate actions to * another RNG object, surrounded by acquire/release/etc. The * class called SDelegated does this using builtin * synchronization rather than Sync locks * so might be a useful comparison. * *
Using Channels *
These classes work a little bit differently than the others. * Each test arranges that half of the threads behave as producers, * and half as consumers. Each test iteration puts/takes an RNG object * through a channel before or after executing its update * method. When the number of threads is one, each producer * simply consumers its own object. Some Channels (notably * SynchronousChannels) cannot be used with only one thread, * in which case the test is skipped. * *
Using Executors *
These classes arrange for each RNG update to occur * as an executable command. Each test iteration passes a * command to an Executor, which eventually executes it. * Execution is overlapped: Each iteration starts a new * command, and then waits for the previous command to complete. * *
* *

* * 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.xml0000644000175000017500000000334310202637333016667 0ustar wbaerwbaer00000000000000 concurrent-dfsg-1.3.4/LockedExecutor.java0000644000175000017500000000313310202157355020627 0ustar wbaerwbaer00000000000000/* File: LockedExecutor.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 within * a synchronization lock and then returns. * *

[ 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 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.java0000644000175000017500000002255210202157355020432 0ustar wbaerwbaer00000000000000/* 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.) *

* 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 restarted. 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.) *

* 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. *

 * 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();
 *    }
 * }
 * 
*

[ 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 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.java0000644000175000017500000001045310202157355023010 0ustar wbaerwbaer00000000000000/* 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. *

[ 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.java0000644000175000017500000000363610202157355020202 0ustar wbaerwbaer00000000000000/* 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: *

 * 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");
 * }
 * 
* *

[ 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.java0000644000175000017500000000173710202157355020650 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000653410202157355017637 0ustar wbaerwbaer00000000000000/* 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. *

 * 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
 *   } 
 * }
 * 
* *

[ 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.java0000644000175000017500000000344010202157355020372 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001007210202157355021164 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001261310202157355021215 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001270210202157355021410 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000153410202157355017726 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001375510202157355020435 0ustar wbaerwbaer00000000000000/* 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 * 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.

* * 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.java0000644000175000017500000002777710202157355020112 0ustar wbaerwbaer00000000000000/* 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 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). *

* 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 restart() is invoked. *

* 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 setDaemon status. *

* 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): *

   * 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. *

* Sample Usage. Here is one way * to update Swing components acting as progress indicators for * long-running actions. *

   * 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.java0000644000175000017500000001116410202157355023154 0ustar wbaerwbaer00000000000000/* 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. *

[ 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.java0000644000175000017500000000475110202157355020305 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001023210202157355021352 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000447310202157355016640 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001005610202157355020574 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000334310202157355022245 0ustar wbaerwbaer00000000000000/* 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 INITIAL_DEFAULT_CAPACITY * @see #INITIAL_DEFAULT_CAPACITY */ public static int get() { return defaultCapacity_.get(); } } concurrent-dfsg-1.3.4/SyncSortedSet.java0000644000175000017500000000630110202157355020460 0ustar wbaerwbaer00000000000000/* 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. *

[ 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.java0000644000175000017500000000537010202157355020101 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001247110202157355021213 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000003175010202157355020061 0ustar wbaerwbaer00000000000000/* 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: *

    *
  • Unlike a CyclicBarrier, is not restricted to use * with fixed-sized groups of threads. * Any number of threads can attempt to enter a rendezvous, * but only the predetermined number of parties enter * and later become released from the rendezvous at any give time. *
  • Enables each participating thread to exchange information * with others at the rendezvous point. Each entering thread * presents some object on entry to the rendezvous, and * returns some object on release. The object returned is * the result of a RendezvousFunction that is run once per * rendezvous, (it is run by the last-entering thread). By * default, the function applied is a rotation, so each * thread returns the object given by the next (modulo parties) * entering thread. This default function faciliates simple * application of a common use of rendezvous, as exchangers. *
*

* 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 restarted. This is usually * the simplest and best strategy for sharing knowledge * about failures among cooperating threads in the most * common usages contexts of Rendezvous. *

* 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. *

 * 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();
 *   }
 * }
 * 
*

[ 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 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.java0000644000175000017500000000764410202157355016577 0ustar wbaerwbaer00000000000000/* 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. *

* 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.java0000644000175000017500000001217310202157355020263 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000332610202157355021311 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001575710202157355017476 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000504410202157355017510 0ustar wbaerwbaer00000000000000/* 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 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. *

* *

[ 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.java0000644000175000017500000001440510202157355017265 0ustar wbaerwbaer00000000000000/* 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 *

    *
  • size *
  • isEmpty *
  • get *
  • containsKey *
  • containsValue *
  • keySet *
  • entrySet *
  • values *
* Writer operations are: *
    *
  • put *
  • putAll *
  • remove *
  • clear *
* *

[ 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.java0000644000175000017500000001212610202157355020114 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000002546610202157355016640 0ustar wbaerwbaer00000000000000/* 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: *

 * 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); } 
 *     });
 *   }
 *   // ...
 * }
 * 
*

* 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. *

 * 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; }
 *     }
 *   }
 * }
 *
*

* Here is an even fancier version, that uses lock re-ordering * upon conflict: *

 * 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; }
 *  }
 *}
 *
*

* 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 *

 *   if (!c.attempt(timeval)) throw new TimeoutException(timeval);
 * 
*

* 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 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. *

* 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()): *

 * 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% 
 *     }
 *   }
 * }
 * 
*

* 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.java0000644000175000017500000000455210202157355020414 0ustar wbaerwbaer00000000000000/* 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: *

    *
  • The methods in a class can be cleanly separated into * those that only access (read) data vs those that * modify (write). *
  • Target applications generally have more readers than writers. *
  • The methods are relatively time-consuming (as a rough * rule of thumb, exceed more than a hundred instructions), so it * pays to introduce a bit more overhead associated with * ReadWrite locks compared to simple synchronized methods etc * in order to allow concurrency among reader threads. * *
* 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. *

* Standard usage: *

 * 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 *

[ Introduction to this package. ] **/ public interface ReadWriteLock { /** get the readLock **/ Sync readLock(); /** get the writeLock **/ Sync writeLock(); } concurrent-dfsg-1.3.4/BoundedLinkedQueue.java0000644000175000017500000002365710202157355021440 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000005002310202157355021240 0ustar wbaerwbaer00000000000000/* 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 setRunPriorities to either * increase or decrease the priorities of active threads, which * may interact with group size choice. *

* 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: *

 * 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. *

* The main supported methods are 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");
 *     }
 *   }
 * }
 * 
*

* Method 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. * *

[ 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 * 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. *

    *
  • For each FJTaskRunner thread (labeled as Tn, for * n from zero to group size - 1): *
      *
    • A star "*" is printed if the thread is currently active; * that is, not sleeping while waiting for work. Because * threads gradually enter sleep modes, an active thread * may in fact be about to sleep (or wake up). *
    • Q Cap The current capacity of its task queue. *
    • Run The total number of tasks that have been run. *
    • New The number of these tasks that were * taken from either the entry queue or from other * thread queues; that is, the number of tasks run * that were not forked by the thread itself. *
    • Scan The number of times other task * queues or the entry queue were polled for tasks. *
    *
  • Execute The total number of tasks entered * (but not necessarily yet run) via execute or invoke. *
  • Time Time in seconds since construction of this * FJTaskRunnerGroup. *
  • Rate The total number of tasks processed * per second across all threads. This * may be useful as a simple throughput indicator * if all processed tasks take approximately the * same time to run. *
*

* 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: *

    *
  • High numbers of scans may mean that there is insufficient * parallelism to keep threads busy. However, high scan rates * are expected if the number * of Executes is also high or there is a lot of global * synchronization in the application, and the system is not otherwise * busy. Threads may scan * for work hundreds of times upon startup, shutdown, and * global synch points of task sets. *
  • Large imbalances in tasks run across different threads might * just reflect contention with unrelated threads on a system * (possibly including JVM threads such as GC), but may also * indicate some systematic bias in how you generate tasks. *
  • Large task queue capacities may mean that too many tasks are being * generated before they can be run. * Capacities are reported rather than current numbers of tasks * in queues because they are better indicators of the existence * of these kinds of possibly-transient problems. * Queue capacities are * resized on demand from their initial value of 4096 elements, * which is much more than sufficient for the kinds of * applications that this framework is intended to best support. *
**/ 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. *

* 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.java0000644000175000017500000000220410202157355021144 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001245210202157355021045 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001246110202157355017636 0ustar wbaerwbaer00000000000000/* 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. *

 * 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;
 *   }
 *
 * }
 *
*

[ 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. release(n) is * equivalent in effect to: *

   *   for (int i = 0; i < n; ++i) release();
   * 
*

* 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.java0000644000175000017500000000526510202157355021404 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000374410202157355017307 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000776610202157355020255 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000425710202157355020141 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000203310202157355022313 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001342610202157355020366 0ustar wbaerwbaer00000000000000/* 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

*

 * 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; }
 *   }
 * }
 * 
*

[ 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.java0000644000175000017500000000552310202157355016747 0ustar wbaerwbaer00000000000000/* 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. *

 * 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. ]

**/ 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.java0000644000175000017500000001147310202157355020427 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001002210202157355020420 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000003276410202157355020653 0ustar wbaerwbaer00000000000000/* 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: *

    *
  • size *
  • isEmpty *
  • toArray *
  • contains *
  • containsAll *
  • iterator *
* The possibly mutative writer operations (which are also * the set of operations that are allowed to throw * UnsupportedOperationException) are: *
    *
  • add *
  • addAll *
  • remove *
  • clear *
  • removeAll *
  • retainAll *
* *

* 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, *

    *
  • All mutative operations convert the interruption to * an UnsupportedOperationException, while also propagating * the interrupt status of the thread. Thus, unlike normal * java.util.Collections, SyncCollections can transiently * behave as if mutative operations are not supported. *
  • All read-only operations * attempt to return a result even upon interruption. In some contexts, * such results will be meaningless due to interference, but * provide best-effort status indications that can be useful during * recovery. The cumulative number of synchronization failures encountered * during such operations is accessible using method * synchronizationFailures(). * Non-zero values may indicate serious program errors. *
*

* 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 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) { ... }
 * 
*

* (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: *

 * Mutex lock = new Mutex();
 * TimeoutSync timedLock = new TimeoutSync(lock, 1000); // 1 sec timeouts
 * Collection c = new SyncCollection(new HashSet(), timedlock);
 * 
*

* The same can be done with read-write locks: *

 * 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);
 * 
*

* 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: *

 * 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);
 *   }
 *   ...
 * }
 * 
* *

[ 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 *

   * 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. *

* Sample Usage *

   * 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.java0000644000175000017500000000254410202157355017463 0ustar wbaerwbaer00000000000000/* 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. *

* 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.java0000644000175000017500000001223010202157355020261 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001155010202157355020124 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001122110202157355025462 0ustar wbaerwbaer00000000000000/* 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: *

 * 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();
 *   }
 * }
 * 
* * *

[ 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.java0000644000175000017500000002177310202157355023614 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000630210202157355020740 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001740710202157355022045 0ustar wbaerwbaer00000000000000/* 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: *

    *
  • When you need or want to offload an instance * variable to use its own synchronization lock. * When these objects are used to replace instance variables, they * should almost always be declared as final. This * helps avoid the need to synchronize just to obtain the reference * to the synchronized variable itself. * *
  • When you need methods such as set, commit, or swap. * Note however that * the synchronization for these variables is independent * of any other synchronization perfromed using other locks. * So, they are not * normally useful when accesses and updates among * variables must be coordinated. * For example, it would normally be a bad idea to make * a Point class out of two SynchronizedInts, even those * sharing a lock. * *
  • When defining static variables. It almost * always works out better to rely on synchronization internal * to these objects, rather than class locks. *
*

* While they cannot, by nature, share much code, * all of these classes work in the same way. *

* Construction
* Synchronized variables are always constructed holding an * initial value of the associated type. Constructors also * establish the lock to use for all methods: *

    *
  • By default, each variable uses itself as the * synchronization lock. This is the most common * choice in the most common usage contexts in which * SynchronizedVariables are used to split off * synchronization locks for independent attributes * of a class. *
  • You can specify any other Object to use as the * synchronization lock. This allows you to * use various forms of `slave synchronization'. For * example, a variable that is always associated with a * particular object can use that object's lock. *
*

* Update methods
* Each class supports several kinds of update methods: *

    *
  • A 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. *

    *

  • A 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 ...  }
     *  }
     * 
    *

    *

  • A swap method that atomically swaps with another * object of the same class using a deadlock-avoidance strategy. *

    *

  • Update-in-place methods appropriate to the type. All * numerical types support: *
      *
    • add(x) (equivalent to return value += x) *
    • subtract(x) (equivalent to return value -= x) *
    • multiply(x) (equivalent to return value *= x) *
    • divide(x) (equivalent to return value /= x) *
    * Integral types also support: *
      *
    • increment() (equivalent to return ++value) *
    • decrement() (equivalent to return --value) *
    * Boolean types support: *
      *
    • or(x) (equivalent to return value |= x) *
    • and(x) (equivalent to return value &= x) *
    • xor(x) (equivalent to return value ^= x) *
    • complement() (equivalent to return x = !x) *
    * 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. *
*

* Guarded methods
* All Waitable subclasses provide notifications on * every value update, and support guarded methods of the form * whenpredicate, that wait until the * predicate hold, then optionally run any Runnable action * within the lock, and then return. All types support: *

    *
  • whenEqual(value, action) *
  • whenNotEqual(value, action) *
* (If the action argument is null, these return immediately * after the predicate holds.) * Numerical types also support *
    *
  • whenLess(value, action) *
  • whenLessEqual(value, action) *
  • whenGreater(value, action) *
  • whenGreaterEqual(value, action) *
* 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. *

* Other methods
* This class implements Executor, and provides an execute * method that runs the runnable within the lock. *

* All classes except SynchronizedRef and WaitableRef implement * 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. * *

* * * *

[ 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.java0000644000175000017500000000213510202157355020561 0ustar wbaerwbaer00000000000000/* 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 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 *

[ 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.java0000644000175000017500000001230310202157355020456 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000500610202157355017470 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001140010202157355020777 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000010046110202157355020652 0ustar wbaerwbaer00000000000000/* 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 execute(Runnable command), which can be * called instead of directly creating threads to execute commands. * *

* Thread pools can be useful for several, usually intertwined * reasons: * *

    * *
  • To bound resource use. A limit can be placed on the maximum * number of simultaneously executing threads. * *
  • To manage concurrency levels. A targeted number of threads * can be allowed to execute simultaneously. * *
  • To manage a set of threads performing related tasks. * *
  • To minimize overhead, by reusing previously constructed * Thread objects rather than creating new ones. (Note however * that pools are hardly ever cure-alls for performance problems * associated with thread construction, especially on JVMs that * themselves internally pool or recycle threads.) * *
* * 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. * *
*
Queueing * *
By default, this pool uses queueless synchronous channels to * to hand off work to threads. This is a safe, conservative policy * that avoids lockups when handling sets of requests that might * have internal dependencies. (In these cases, queuing one task * could lock up another that would be able to continue if the * queued task were to run.) If you are sure that this cannot * happen, then you can instead supply a queue of some sort (for * example, a BoundedBuffer or LinkedQueue) in the constructor. * This will cause new commands to be queued in cases where all * MaximumPoolSize threads are busy. Queues are sometimes * appropriate when each task is completely independent of others, * so tasks cannot affect each others execution. For example, in an * http server.

* * 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.

* *

Maximum Pool size * *
The maximum number of threads to use, when needed. The pool * does not by default preallocate threads. Instead, a thread is * created, if necessary and if there are fewer than the maximum, * only when an 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.

* *

Minimum Pool size * *
The minimum number of threads to use, when needed (default * 1). When a new request is received, and fewer than the minimum * number of threads are running, a new thread is always created to * handle the request even if other worker threads are idly waiting * for work. Otherwise, a new thread is created only if there are * fewer than the maximum and the request cannot immediately be * queued.

* *

Preallocation * *
You can override lazy thread construction policies via * method createThreads, which establishes a given number of warm * threads. Be aware that these preallocated threads will time out * and die (and later be replaced with others if needed) if not used * within the keep-alive time window. If you use preallocation, you * probably want to increase the keepalive time. The difference * between setMinimumPoolSize and createThreads is that * createThreads immediately establishes threads, while setting the * minimum pool size waits until requests arrive.

* *

Keep-alive time * *
If the pool maintained references to a fixed set of threads * in the pool, then it would impede garbage collection of otherwise * idle threads. This would defeat the resource-management aspects * of pools. One solution would be to use weak references. However, * this would impose costly and difficult synchronization issues. * Instead, threads are simply allowed to terminate and thus be * GCable if they have been idle for the given keep-alive time. The * value of this parameter represents a trade-off between GCability * and construction time. In most current Java VMs, thread * construction and cleanup overhead is on the order of * milliseconds. The default keep-alive value is one minute, which * means that the time needed to construct and then GC a thread is * expended at most once per minute. *

* * To establish worker threads permanently, use a negative * argument to setKeepAliveTime.

* *

Blocked execution policy * *
If the maximum pool size or queue size is bounded, then it * is possible for incoming 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:

* *

*
Run (the default) *
The thread making the execute request * runs the task itself. This policy helps guard against lockup. *
Wait *
Wait until a thread becomes available. This * policy should, in general, not be used if the minimum number of * of threads is zero, in which case a thread may never become * available. *
Abort *
Throw a RuntimeException *
Discard *
Throw away the current request and return. *
DiscardOldest *
Throw away the oldest request and return. *
* * Other plausible policies include raising the maximum pool size * after checking with some other objects that this is OK.

* * 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 * 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.

* *

Thread construction parameters * *
A settable ThreadFactory establishes each new thread. By * default, it merely generates a new instance of class Thread, but * can be changed to use a Thread subclass, to set priorities, * ThreadLocals, etc.

* *

Interruption policy * *
Worker threads check for interruption after processing each * command, and terminate upon interruption. Fresh threads will * replace them if needed. Thus, new tasks will not start out in an * interrupted state due to an uncleared interruption in a previous * task. Also, unprocessed commands are never dropped upon * interruption. It would conceptually suffice simply to clear * interruption between tasks, but implementation characteristics of * interruption-based methods are uncertain enough to warrant this * conservative strategy. It is a good idea to be equally * conservative in your code for the tasks running within pools. *

* *

Shutdown policy * *
The interruptAll method interrupts, but does not disable the * pool. Two different shutdown methods are supported for use when * you do want to (permanently) stop processing tasks. Method * shutdownAfterProcessingCurrentlyQueuedTasks waits until all * current tasks are finished. The shutDownNow method interrupts * current threads and leaves other queued requests unprocessed. *

* *

Handling requests after shutdown * *
When the pool is shutdown, new incoming requests are handled * by the blockedExecutionHandler. By default, the handler is set to * discard new requests, but this can be set with an optional * argument to method * shutdownAfterProcessingCurrentlyQueuedTasks.

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: * *

 * class MyPool {
 *   // initialize to use a maximum of 8 threads.
 *   static PooledExecutor pool = new PooledExecutor(8);
 * }
 * 
* Here are some sample variants in initialization: *
    *
  1. Using a bounded buffer of 10 tasks, at least 4 threads (started only * when needed due to incoming requests), but allowing * up to 100 threads if the buffer gets full. *
     *        pool = new PooledExecutor(new BoundedBuffer(10), 100);
     *        pool.setMinimumPoolSize(4);
     *     
    *
  2. Same as (1), except pre-start 9 threads, allowing them to * die if they are not used for five minutes. *
     *        pool = new PooledExecutor(new BoundedBuffer(10), 100);
     *        pool.setMinimumPoolSize(4);
     *        pool.setKeepAliveTime(1000 * 60 * 5);
     *        pool.createThreads(9);
     *     
    *
  3. Same as (2) except clients abort if both the buffer is full and * all 100 threads are busy: *
     *        pool = new PooledExecutor(new BoundedBuffer(10), 100);
     *        pool.setMinimumPoolSize(4);
     *        pool.setKeepAliveTime(1000 * 60 * 5);
     *        pool.abortWhenBlocked();
     *        pool.createThreads(9);
     *     
    *
  4. An unbounded queue serviced by exactly 5 threads: *
     *        pool = new PooledExecutor(new LinkedQueue());
     *        pool.setKeepAliveTime(-1); // live forever
     *        pool.createThreads(5);
     *     
    *
* *

* 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: * *

   *   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.java0000644000175000017500000000377410202157355017310 0ustar wbaerwbaer00000000000000 /* 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: *
    *
  • Every barrier is defined for a given number * of 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.) *
  • A barrier can become 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. *
*

[ 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.java0000644000175000017500000001040410202157355021520 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000177610202157355023543 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000631210202157355020444 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000000254010202157355021215 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000004431610202157355017041 0ustar wbaerwbaer00000000000000/* 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 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. *

* There are three different ways to run a FJTask, * with different scheduling semantics: *

    *
  • FJTask.start() (as well as FJTaskRunnerGroup.execute(FJTask)) * behaves pretty much like Thread.start(). It enqueues a task to be * run the next time any FJTaskRunner thread is otherwise idle. * It maintains standard FIFO ordering with respect to * the group of worker threads. *
  • FJTask.fork() (as well as the two-task spawning method, * coInvoke(task1, task2), and the array version * coInvoke(FJTask[] tasks)) starts a task * that will be executed in * procedure-call-like LIFO order if executed by the * same worker thread as the one that created it, but is FIFO * with respect to other tasks if it is run 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(), but can only be * used when these scheduling semantics are acceptable. *
  • FJTask.invoke(FJTask) just executes the run method * of one task from within another. It is the analog of a * direct call. *
*

* 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 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.java0000644000175000017500000000532510202157355021030 0ustar wbaerwbaer00000000000000/* 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. *

*

[ 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.java0000644000175000017500000001435710202157355020670 0ustar wbaerwbaer00000000000000/* 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 * 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. *

* 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.html0000644000175000017500000016237610202157355017104 0ustar wbaerwbaer00000000000000 Overview of package util.concurrent Release 1.3.4.

Overview of package util.concurrent Release 1.3.4.

by Doug Lea

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:

  • 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
Plus some utilities and frameworks that build upon these.

If you arrived at page
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
EDU.oswego.cs.dl.util.concurrent
is available in (tar.gz format) or (zip format).

It is currently distributed in source form only. To build it, use a Java 1.2+ compiler to:

  javac -d [SOMEWHERE IN YOUR CLASSPATH] *.java
Or use this ant build file donated by Travell Perkins.

The classes in the misc directory can be built the same way.

To use it, add to java files:

  import EDU.oswego.cs.dl.util.concurrent.*

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:

  javadoc -public -d [BASE OF SOME JAVADOC PATH] *.java

Contents

Sync
Interface for classes used as exclusion, resource management, and related synchronization aids, supporting methods acquire, attempt(msecs), and release.

Implementations

Semaphore
Default implementation of Semaphores, providing no special ordering guarantees.
WaiterPreferenceSemaphore
Provides protection against barging (infinite overtaking)
FIFOSemaphore
Provides first-in/first-out ordering
PrioritySemaphore
Prefers notifications to higher-priority threads
Mutex
Basic non-reentrant mutual exclusion lock
ReentrantLock
Java-style per-thread mutual exclusion lock
Latch
A condition that is acquirable forever more after the first release
CountDown
A condition that is acquirable forever more after the nth release.

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:

NullSync
A no-op implementation: acquire and attempt always succeed.
TimeoutSync
Routes all calls to acquire to use attempt with a predefined timeout value.
LayeredSync
Cascades operations of two Syncs
ObservableSync
Issues calls to SyncObservers upon each acquire and release.

Related Classes

CondVar
Support for POSIX (pthreads) style condition variables
TimeoutException
A standardized time-out exception class

ReadWriteLock
Interface for pairs of locks, one for reading, and one for writing.

Implementations

WriterPreferenceReadWriteLock
The most useful and common policy
ReentrantWriterPreferenceReadWriteLock
Allows multiple lock holds as well as lock downgrading by writers.
ReaderPreferenceReadWriteLock
Prefers waiting readers to waiting writers.
FIFOReadWriteLock
Prefers earliest threads (whether readers or writers).

Barrier
Synchronization points for groups of threads.

Implementations

CyclicBarrier
A tool to force multiple threads to synchronize at a given point
Rendezvous
A cyclic barrier that does not rely on there being a predetermined number of participant threads, and allows threads to exchange information at each barrier point.

Related Classes

BrokenBarrierException
A standardized exception for barrier synchronization failures

Channel
Interface for queues, buffers, conduits and pipes supporting blocking 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.

Implementations

LinkedQueue
An unbounded linked-list-based queue. This is usually the best choice for a general-purpose queue.
BoundedLinkedQueue
A linked queue with a capacity bound
BoundedBuffer
An array-based bounded buffer
Slot
A one-slot bounded buffer. (Note that this can also serve as a restricted form of Synchronized variable.)
SynchronousChannel
A zero-slot CSP/Ada-style channel in which every put must wait for a take, and vice versa.
BoundedPriorityQueue
A channel based on a Heap data structure. Elements must either be Comparable, or comparable using a supplied Comparator
WaitFreeQueue
An unbounded linked-list-based queue relying on atomic commits and retries rather than wait/notify.

Related Classes

DefaultChannelCapacity
A utility class that makes it easier to set default capacities for channels that have a capacity that must otherwise be set in constructors.

Executor
Interface for objects that execute Runnable commands.

Implementations

DirectExecutor
An implementation that just directly runs command in current thread.
LockedExecutor
An implementation that directly runs command within a supplied Sync lock in current thread.
ThreadedExecutor
An implementation that runs each command in a new thread.
QueuedExecutor
An implementation that queues commands for execution by a single background thread.
PooledExecutor
A tunable, extensible thread pool class

Related classes

Callable
Interface for runnable actions that return results
FutureResult
Holder for results of actions that can be set by Callables.
ThreadFactory
Interface for objects that create Thread objects
ThreadFactoryUser
Convenient base for classes that use ThreadFactories.
ClockDaemon
A utility for executing commands at given times, after given delays, or periodically with given cycles.
TimedCallable
Invokes a Callable in its own thread, but cancels it if not completed by a given maximum time.

Fork/Join Tasks
A fast lightweight task framework built upon Java threads, and geared for parallel computation.
FJTask
Abstract Base class for tasks.
FJTaskRunnerGroup
Control class for running Tasks.
FJTaskRunner
Underlying specialized Thread subclass for running Tasks.
Demos and examples
A directory of sample programs that use the Task framework. (See also a paper on the design and performance of this framework.)

Collections
Implementations of java.util.Collection and related classes that can help solve concurrency problems.
ConcurrentReaderHashMap
An analog of java.util.Hashtable that allows retrievals during updates.
ConcurrentHashMap
An analog of java.util.Hashtable that allows both concurrent retrievals and concurrent updates.
CopyOnWriteArrayList
A copy-on-write analog of java.util.ArrayList
CopyOnWriteArraySet
A java.util.Set based on CopyOnWriteArrayList.
SyncCollection
A wrapper class placing either Syncs or ReadWriteLocks around java.util.Collection
SyncSet
A wrapper around java.util.Set
SyncSortedSet
A wrapper around java.util.SortedSet
SyncList
A wrapper around java.util.List
SyncMap
A wrapper around java.util.Map
SyncSortedMap
A wrapper around java.util.SortedMap
Related classes
PropertyChangeMulticaster
A copy-on-write replacement for java.beans.PropertyChangeSupport
VetoableChangeMulticaster
A copy-on-write replacement for java.beans.VetoableChangeSupport

SynchronizedVariable
Simple synchronized analogs of Number and Ref classes in java.lang. Each has a subclass that in addition to maintaining synchronization, also provides notifications upon value changes and supports guarded waits.

Miscellany
There are some classes in the misc directory that might be of interest but aren't really part of this package. They include:
  • SynchronizationTimer, that can be used to experiment with different synchronization schemes. It requires Swing (JFC). (To run it, compile misc/*.java, and then java EDU.oswego.cs.dl.util.concurrent.misc.SynchronizationTimer .)
  • An immutable Fraction class.
  • Joe Bowbeer's SwingWorker class, discussed in his "The Last Word in Swing Threads" article.
  • Other implementations of the above interfaces that are not valuable or stable enough to include here.
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

  • All classes are released to the public domain and may be used for any purpose whatsoever without permission or acknowledgment. Portions of the CopyOnWriteArrayList and ConcurrentReaderHashMap classes are adapted from Sun JDK source code. These are copyright of Sun Microsystems, Inc, and are used with their kind permission, as described in this license.

  • Version numbers for this package are of the form Major.minor.fix. Fix numbers reflect corrections of small errors and release problems (missing files, portability enhancements, etc). Minor numbers are incremented on additions. Major numbers reflect serious incompatibilities and restructurings. I may also sometimes make minor updates to this page and related files before packaging up all files as a release. During early releases of added classes, I expect to make frequent small changes and releases, as soon as problems are noticed. Other ongoing changes are reflected in individual source files, that you can get individual updates on if you need them.

  • Most of the interfaces and classes contain usage notes and examples. I hope to add more. Please send suggestions to dl@cs.oswego.edu

  • You can get e-mail notification when this page (or any other URL for that matter) changes via ChangeDetecion.com or other such services.

  • These have been tested with JDK1.2+, but all except those relying on JDK1.2 java.util.collections (i.e., BoundedPriorityQueue and CopyOnWriteArrayList) should also work with JDK1.1.x. Workarounds exist for those relying on collections by obtaining the backported 1.1 versions and follow the instructions. You can then use "sed" or somesuch to replace all occurrences of "java.util." with "com.sun.java.util". Also, I'm told that some 1.1 compilers have some problems compiling some of the blank finals used. And while the 1.1port of collections also includes a 1.2-compliant version of java.util.Random, you can alternatively use the following version contributed by Andrew Cooke:
    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 ;
      }
    
    }
    

    Konstantin Läufer has generously placed a version compiled for JDK1.1 at http://www.cs.luc.edu/~laufer/courses/337/handouts/concurrent11.zip

  • Many of these classes are adapted from versions described in the second edition of Concurrent Programming in Java (CPJ) and examples from tutorials based on the book.

  • Several classes were developed with the help of David Holmes and Joe Bowbeer. Many have benefited from discussions and comments from other people, including Tom Cargill, Tom May, Wayne Boucher, Matthias Ernst, Michael Banks, Richard Emberson, Piotr Kaminski, Bill Pugh, Peter Buhr, Alexander Terekhov, Alex Yiu-Man Chan, Andrew Kelly, Markos Kapes, Boris Dimitshteyn.

Some Questions and Answers about Design and Implementation

Isn't it annoying that so many methods throw InterruptedException?
Maybe, but synchronization points are among the best points to detect interruption. Since this a package of synchronization aids, most methods detect interruption as early and often as reasonable to help avoid becoming stuck when the thread should be stopping anyway. In particular, interruption is normally checked before trying to obtain locks used in Syncs, which minimizes the vulnerability window for getting stuck when an activity is cancelled. (Between this and the finite durations that internal java synchronization locks are held in Sync classes, it is normally impossible for threads to become stuck waiting on internal locks when they have been interrupted.) These classes fail cleanly upon interruption. Normally, all you need to do upon catching an InterruptedException is either rethrow it, or clean up and then set Thread.currentThread().interrupt() to propagate status.

If you need to invoke such methods even when the thread is in an interrupted state (for example, during recovery actions) you can do:

  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();
    }
 }

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.

Why is there so much near-duplication of code?
You'd think there would be some nice way to unify more classes to share significant aspects of synchronization mechanics. But standard lines of attack for doing this turn out unsatisfying at best. The main reason for creating this package is that even simple classes involving concurrency control mechanics are sometimes tedious, repetitive, tricky, and/or error-prone to write, so it is nice to have them written already.

Why do most methods return false/null after timeouts rather than throwing TimeoutException?
Because I think it would normally be misleading to throw exceptions. In Java, timeout arguments merely provide hints about when threads should be woken to check out the state of the world. Due to scheduling delays, threads need not resume immediately after their timeouts elapse, so real-time-based timeout exceptions would not be appropriate. The simplest course of action is just to report whether the condition the thread is waiting for does hold after waiting for at least this period. Returning false/null is not necessarily an exceptional situation. In those classes where it is exceptional (in some classes layered on top of basic Syncs and Channels) failed timeouts are converted to TimeoutExceptions. You can do the same in your own code using these classes. As of version 1.1.0, this is made simpler to carry out, since TimeoutException now extends InterruptedException.

Why aren't there deadlock-detecting Syncs or related classes for detecting lockups?
Because timeouts appear to be more generally useful. In fact, it is hard to imagine contexts where deadlock detection is a better option than timeouts in Java. A timeout can serve as a heuristic deadlock detection device, but can also serve to detect stalled IO, network partitions, and related failures. Program responses to deadlock are hardly ever different than responses to these other failures. So, it is usually a good idea to use timeouts as general-purpose heuristic detectors for all liveness problems, subdividing responses to particular failures (for example, by subclassing TimeoutException), only when necessary. Additionally, there are two problems with implementing deadlock-detecting Syncs that make them unattractive choices: (1) They can only detect deadlock among uses of the particular Sync classes being used, so cannot deal with deadlocks involving builtin synchronization (2) lock cycle detection adds overhead to each lock acquire and release. The main context in which deadlock detection would be useful is during program debugging, but here, it would be better to rely on specially instrumented JVMs. (Note that it is easy to transform code that relies on acquire to instead use timeouts via the TimeoutSync class. This can be a good way to make code more robust with respect to locking problems.)

Why isn't there a distinct Lock or MutualExclusionLock interface?
Because many objects implementing the Sync interface can be used as locks if they are in appropriate states, but not all of them can always be used as such. Additionally, there are several senses of mutual exclusion (for example, reentrant vs non-reentrant, full vs read/write). Since there is no way to say that a given class only sometimes conforms to the intended sense of a subinterface, the flexibility and simplicity of only using a single principle interface (Sync) for all such types outweighs the potential advantages of finer-grained categorizations.

Why do so many methods perform notify within InterruptedException catches?
Because when notify's and interrupt's happen at about the same time, JVMs are currently free to treat them independently, so a notified thread could return out as interrupted. In classes using notify rather than notifyAll, the extra notify in the catch clause is a safeguard to ensure that a non-interrupted thread, if one exists, will be notified. See my CPJ book for more details.

How efficient are these classes?
Most of these classes use the most efficient implementations I know of for general-purpose concurrent programming, yet also try to be conservative about differences across common JVMs, and to minimize surprising limitations and side-effects. This is always a bit of a trade-off though. Some could be made more efficient at the cost of supporting fewer operations, relying on properties of particular JVMs, or having more usage constraints. Conversely some could support more contexts or operations, or simpler usage, at the cost of efficiency.

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 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.

Are there any programming errors?
I don't believe so. Please try to prove me wrong. If you are the first person to discover a particular coding error in a current release, I'll send you a free copy of my CPJ book. Also, I would greatly appreciate receiving any sample applications that can help serve as useful tests, so as to build up a more extensive test suite.

Should I worry about the use of volatile in these classes?
Many JVMs are known not to correctly implement the JLS spec (either the original or the upcoming revision) for volatile fields. However, volatiles are used in conservative ways in this package, that don't encounter problems at least on recent Sun and IBM JVMs.

Why do classes declare practically all internal matters as protected?
While probably 99% of the uses of these classes should just treat them as black-box utility components, these classes are intended to be extensible, to allow more specialized synchronization control to be customized for different applications. However, it takes a lot of expertise to extend or modify most of them via subclassing. If you do try to extend, consider first running javadoc on these classes with switches that generate documentation for non-public classes, methods, and fields. Also, if you encounter problems making subclasses due to inflexibility in base classes, I'd like to hear about it, so I can try to come up with a better factoring.

Why aren't most classes Serializable?
I don't know what to about this. On one hand, it wouldn't make sense in a lot of contexts to serialize, say, a Semaphore. On the other hand, maybe it ought not be precluded. Opinions welcome. One suggestion is to only declare as serializable those classes specifically designed to work with other persistent or distributed concurrency control frameworks. (No such classes currently exist.)

Why didn't using ReadWriteLocks instead of plain synchronization speed up my program?
ReadWriteLocks have more overhead than do synchronized methods or blocks. They pay off only when the code being protected by the locks is time-consuming, and when readers outnumber writers, so the increased concurrency outweighs the increased bookkeeping. (They are also sometimes of use in avoiding deadlock.) Special-purpose data structures such as the Concurrent hash tables in this package have far less overhead, and typically much better performance than placing ReadWriteLocks around most sequential data structures.

Are instances of these classes externally lockable -- that is, can I control object x via synchronized(x) { ... } ?
Not necessarily. Some objects rely on their own synchronization locks, some rely on internal locks, some rely on other synchronization objects. So in general, you cannot know the effect of synchronized(x) and so probably ought never use it.

Why do I get strict alternation of producer and consumer threads when using buffered channels such as BoundedBuffer?
Although it depends on details of JVM scheduling policies, this is the most likely result when producer and consumer actions both take about the same amount of time to process, since both put and take operations signal waiting threads. The point of buffering is to decouple producers and consumers when one or the other is bursty, so temporarily gets ahead or behind its average rate. (If the average rates of producers and consumers are not approximately equal, buffering is not of much use.) While it again relies on JVM details, unbounded buffers (for example LinkedQueue) typically do not result in alternation, allowing producers to get arbitrarily ahead of consumers, at the expense of potential resource exhaustion.

Why aren't there timeout methods supporting nanosecond arguments?
Because most JVMs only time to millisecond accuracy (at best) anyway. If this changes, nanosecond versions could be added.

Why is the package named EDU..., not edu?
I've been using the initially-recommended upper-case EDU prefix for a long time for my packages. It would take a lot of busy-work to convert everything to the now-recommended practice of using lower-case. Someday I will do this though.

Why do you use those ugly underscores?!
Because otherwise I tend to make coding mistakes surrounding instance variables versus local variables. See my Sample Java Coding Standard. But I think I've decided to reform :-) Newer classes use a more JDK-like set of conventions.

Why don't you supply Ant build scripts? Or Jar files? Or rearrange into separate src/doc/lib directories? Or CVS? Or ...?
There are too many different ways people would like to use this package for me to keep up with. So I release it in a simple way that should be very easy to adapt to all sorts of different needs and conventions.

Is this code in any way tied to Sun JDK releases?
No. The acknowlegdment to Sun Labs in headers recognizes their generous donations of equipment and release time support that help make this work possible. But this software is not in any way tied to Sun. However, work is underway to create a JSR with the goal of including a similar package in a future JDK release.

Can I use this code in commercial products?
Yes. Many people appear to do so.

Do I need a license to use it? Can I get one?
No!

Can I get commercial support for this package?
I don't know of any place to get it. I can't think of any technical reason that you'd want it.

Sources

History

  • 10Jul1998 1.0
  • 11Jul1998 1.0.1: removed .class files from release, Fixed documentation error, included Barrier interface.
  • 12Jul1998 1.0.2: Fixed return value for swap; fixed documentation errors.
  • 15Jul1998 1.0.3: Fixed more documentation errors; re-fixed swap; other cosmetic improvements.
  • 18Jul1998 1.0.4: Simplified some classes by removing some alleged optimizations that do not actually help on some platforms; improved SynchronizationTimer; added some documentation.
  • 1Sep1998 version 1.1.0:
    • Replace SynchronousChannel algorithm with fairer, more scalable one
    • TimeoutException now extends InterruptedException
    • Replace int counters with longs to avoid wrapping.
    • new LayeredSync class
    • new ObservableSync class
    • new NullSync class
    • new TimeoutSync class
    • new SyncCollection classes
    • new ReentrantWriterPreferenceReadWriteLock class
    • peek added to Channel
    • new ClockDaemon class
    • Refactorings to standardize usage of thread factories
    • removed reliance on ThreadGroups in PooledExecutor
  • 7Jan 1999 Version 1.2
    • ClockDaemon.shutdown allows immediate restart
    • Callable.call throws Throwable, not Exception
    • new Task, TaskRunner, TaskRunnerGroup classes
    • new taskDemo subdirectory
  • 13Jan1999 version 1.2.1
    • Minor cleanup of Task classes
  • 17Jan1999 version 1.2.2:
    • Simplify Task classes; improve documentation; add priority control; they are no longer labeled as `preliminary'.
    • More sample programs in taskDemos
    • Add warnings about reentrancy to RW locks
    • Callable throws Exception again, but FutureResult handles Throwables
  • 25Mar1999 version 1.2.3
    • PooledExecutor -- allow pool to shrink when max size decreased
    • Task -- add reset, array-based operations
    • new PropertyChangeMulticaster, VetoableChangeMulticaster
  • 21may1999 version 1.2.4
    • PooledExecutor -- allow supplied Channel in constructor; new methods createThreads(), drain()
    • Task, TaskRunner, TaskRunnerGroup renamed to FJTask, FJTaskRunner, FJTaskRunnerGroup to avoid clashes with commonly used class name of `Task'.
    • Misc documentation improvements
    • WriterPreferenceReadWriteLock -- fix to notify on interrupt
  • 23oct1999 version 1.2.5
    • PooledExecutor -- add minimumPoolSize settings
    • LU in taskDemo
    • Minor improvements to LinkedQueue, FJTaskRunner
  • 29dec1999 version 1.2.6
    • FJTaskRunner -- now works on MP JVMs that do not correctly implement read-after-write of volatiles.
    • added TimedCallable
  • 12jan2001 version 1.3.0
    • new ConcurrentHashMap, ConcurrentReaderHashMap classes.
    • BoundedLinkedQueue.setCapacity: immediately reconcile permits.
    • ReentrantWriterPreferenceReadWriteLock: Both readers and writers are now reentrant.
    • PooledExecutor: policy now an interface, not abstract class.
    • QueuedExecutor, PooledExecutor: new shutdown methods
  • 2dec2001 Version 1.3.1
    • PooledExecutor: declare inner class constructor as protected, more flexible shutdown support, blocked exec handlers can throw InterruptedExceptions.
    • Ensure all serialization methods are private.
    • Joe Bowbeer's SwingWorker now in misc
    • Improvements to ConcurrentHashMap, ConcurrentReaderHashMap, FIFOReadWriteLock, ReentrantWriterPreferenceReadWriteLock. WaitFreeQueue, SynchronousChannel.
  • 12dec2002 Version 1.3.2
    • SemaphoreControlledChannel - fix constructor to use longs, not ints.
    • Improvements to Heap.
    • Fix interference check in ConcurrentReaderHashMap.
    • ReentrantWriterPreferenceReadWriteLock throw IllegalStateException instead of NullPointerException on release errors.
  • 20feb2004 Version 1.3.3
    • PooledExecutor: Create new threads if needed when terminating. (Thanks to Bruno Dumon), and replace dying thread if it is only one.
    • Clarify by-permission wordings.
    • Fix synchronization scope error in SynchronizedLong (Thanks to Aaron Greenhouse.)
  • 20may2004 Version 1.3.4
    • WaitableX: notify on bitwise operations
    • QueuedExecutor: can shutdown before thread created (thanks to Wolfgang Hoschek)
  • Coming attractions
    • This package is entering maintenance mode because improved versions of main functionality are part of JDK1.5 java.util.concurrent via JSR 166.
concurrent-dfsg-1.3.4/ReentrantLock.java0000644000175000017500000000721210202157355020464 0ustar wbaerwbaer00000000000000/* 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. *

[ 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. release(n) is * equivalent in effect to: *

   *   for (int i = 0; i < n; ++i) release();
   * 
*

* @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.java0000644000175000017500000001645110202157355017252 0ustar wbaerwbaer00000000000000/* 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. *

 * 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 *

[ 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 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.java0000644000175000017500000001222210202157355017010 0ustar wbaerwbaer00000000000000/* 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. *

* 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. *

 * 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 ...
 * }
 * 
*

* @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.java0000644000175000017500000000441410202157355017255 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000007071110202157355020231 0ustar wbaerwbaer00000000000000/* 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: *

    *
  • Fork a FJTask: *
     *  Push task onto DEQ
     *  
    *
  • Get a task to run (for example within taskYield) *
     *  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
     *  
    *
* 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. *

* 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: *

 *     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)
 * 
*

* 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 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. *

* 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 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. *

* 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 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. *

* 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 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.java0000644000175000017500000000177110202157355020454 0ustar wbaerwbaer00000000000000/* 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. *

* [ 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.java0000644000175000017500000000224010202157355017404 0ustar wbaerwbaer00000000000000 /* 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.java0000644000175000017500000002537310202157355017271 0ustar wbaerwbaer00000000000000/* 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: *

 * 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();
 *   }
 * }
 * 
*

* 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: *

 *  try {
 *    for (;;) {
 *       Object item = channel.poll(0);
 *       if (item != null)
 *         process(item);
 *       else
 *         break;
 *    }
 *  }
 *  catch(InterruptedException ex) { ... }
 * 
*

* However, it is possible to determine whether an item * exists in a Channel via 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. *

* When appropriate, you can define an isEmpty method to * return whether peek returns null. *

* Also, as a compromise, even though it does not appear in interface, * implementation classes that can readily compute the number * of elements support a size() method. This allows careful * use, for example in queue length monitors, appropriate to the * particular implementation constraints and properties. *

* 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 *

 * 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
 * 
*

* 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: *

 * 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;
 *      }
 *    }
 * 
*

* Sample Usage. Here is a producer/consumer design * where the channel is used to hold Runnable commands representing * background tasks. *

 * 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();
 *   }
 * }
 *    
 * 
*

[ 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.java0000644000175000017500000000775510202157355022054 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000002437610202157355021546 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001016510202157355021671 0ustar wbaerwbaer00000000000000/* 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.java0000644000175000017500000001312510202157355021054 0ustar wbaerwbaer00000000000000/* 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; } }