bing wang | 5 Jan 2009 10:24
Picon

10 years later after Aglets ---the new techs for migration of Java Objects across JVMs

10 years later  after Aglets ---the Tech for migration of Java Objects
 across JVMs(Object level mobility)
Mobility and migration of Java object is a grundstein for  many others
,such as Mobile Agent and loadballance.
There have been lots of efforts towards the mobility of Java Object
,IBM's Aglets Architecture and ObjectSpace's Voyager System,ProActive
,to name a few. some are commercial software ,some are not maintained
anymore.
At the drawn of the Java 7 ,I would like to cast a brick on the
migration of Java Objects  across JVMs. what new insight and new
technics we have gained after ten years' advance?

I would mark some of Point I thought is important and raise some opent
questions that puzzled me .

I notice that all the ways falls in two catalogues, the way with the
modification of  the semantic of JVM   and the ways keeping the
semantics by introducing restriction to how the Object would looks
like.
I would like to focus on several concern of  the later.

one way to achieve the  migration is to exactly copy the state of the
Object .and create a new one with the state in the destination while
eradicating the original  in an eligant way . Eligance ,here ,means
that before and after the migration  , the Object should keep 2 kinds
of consistency: first , the consistency of the inside state  ,and
second,apears consistency  in the communication with other Objects
outside.
for example, a forwarder could help to forward the calls to the new
place and a naming service should tell others that he has change his
(Continue reading)

Doug Lea | 6 Jan 2009 16:08
Favicon

jsr166y reorganization and updates

Most of the promised updates and reorganization of jsr166y
for Java7 described last month are now in place.
Package jsr166y contains only those classes slated to
be included in Java7: TransferQueue, Phaser, and
the overhauled basic ForkJoin framework. These will
eventually be renamed again to be in Java7 java.util.concurrent.
Classes that didn't make it for inclusion (mainly
ParallelArray et al) are still available in
package extra166y.

ConcurrentReferenceHashMap is not yet included
but is due up next. Also, the proposed Fences
API cannot be included in jsr166y prereleases but
must await integration with Java7 java.util.concurrent.

The main changes in ForkJoin support managed
blocking and parallelism maintenance, which
in turn enables ForkJoinPool to be declared
as ExecutorService and ForkJoinTask as Future.
This also led to some method name changes
to conform to Executor conventions. (For example,
the method originally invoke, then forkJoin,
is now back to invoke :-) ForkJoinTask now
better supports extension, so only the two
most common flavors, RecursiveTask and RecursiveAction
are supplied -- others can now be added by those
wanting to introduce new styles of FJ processing
(although this needs better documentation).

See the usual places:
(Continue reading)

Tim Peierls | 6 Jan 2009 16:29
Gravatar

Re: jsr166y reorganization and updates

On Tue, Jan 6, 2009 at 10:08 AM, Doug Lea <dl <at> cs.oswego.edu> wrote:
This also led to some method name changes to conform to Executor conventions. (For example, the method originally invoke, then forkJoin, is now back to invoke :-)

:-( Sorry to hear that. I argued for the name FJTask.forkJoin, because it is self-explanatory, and I don't see how it violates Executor conventions. FJTask.invoke() looks a lot like FJPool.invoke(FJTask), which is (subtly) different.

--tim
_______________________________________________
Concurrency-interest mailing list
Concurrency-interest <at> cs.oswego.edu
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Doug Lea | 6 Jan 2009 16:53
Favicon

Re: jsr166y reorganization and updates

Tim Peierls wrote:
>
> :-( Sorry to hear that. 

Reasoning:
ForkJoinPool implements ExecutorService method
   invokeAll(Collection<Runnable>),
ForkJoinTask implements the analogous form
   invokeAll(Collection<ForkJoinTask>)
and also the var-arg version
   invokeAll(ForkJoinTask ...)
which is further specialized to the two-task case
   invokeAll(ForkJoinTask t1, ForkJoinTask t2)
So the specialization for the one-task case would be
   invokeAll(ForkJoinTask t)
or the less odd-sounding
   invoke(ForkJoinTask t)
or using more standard OO conventions
   t.invoke().
which differs from
   ForkJoinPool.invoke(ForkJoinTask t)
in that t.invoke() always begins execution in the
current thread, while FJP.invoke(t) might not (and
usually doesn't).

-Doug
Tim Peierls | 6 Jan 2009 19:54
Gravatar

Re: jsr166y reorganization and updates

OK, thanks. I'll try playing with it to see if it still seems confusing.


--tim

On Tue, Jan 6, 2009 at 10:53 AM, Doug Lea <dl <at> cs.oswego.edu> wrote:
Tim Peierls wrote:

:-( Sorry to hear that.

Reasoning:
ForkJoinPool implements ExecutorService method
 invokeAll(Collection<Runnable>),
ForkJoinTask implements the analogous form
 invokeAll(Collection<ForkJoinTask>)
and also the var-arg version
 invokeAll(ForkJoinTask ...)
which is further specialized to the two-task case
 invokeAll(ForkJoinTask t1, ForkJoinTask t2)
So the specialization for the one-task case would be
 invokeAll(ForkJoinTask t)
or the less odd-sounding
 invoke(ForkJoinTask t)
or using more standard OO conventions
 t.invoke().
which differs from
 ForkJoinPool.invoke(ForkJoinTask t)
in that t.invoke() always begins execution in the
current thread, while FJP.invoke(t) might not (and
usually doesn't).

-Doug


_______________________________________________
Concurrency-interest mailing list
Concurrency-interest <at> cs.oswego.edu
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Doug Lea | 7 Jan 2009 17:11
Favicon

Re: jsr166y reorganization and updates

> Tim Peierls wrote:
>>
>> :-( Sorry to hear that. 

I did a documentation improvement pass, including
a brief walkthrough of the join/invoke variants, and
also regularizing/moving methods that I had forgotten
to do before yesterdays's check-in. Let me know if
this helps.

http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166ydocs/jsr166y/ForkJoinTask.html

-Doug
Tim Peierls | 7 Jan 2009 21:16
Gravatar

Re: jsr166y reorganization and updates

It helps.


I think s/each others/each other's/ in the class comment.

--tim

On Wed, Jan 7, 2009 at 11:11 AM, Doug Lea <dl <at> cs.oswego.edu> wrote:
Tim Peierls wrote:

:-( Sorry to hear that.

I did a documentation improvement pass, including
a brief walkthrough of the join/invoke variants, and
also regularizing/moving methods that I had forgotten
to do before yesterdays's check-in. Let me know if
this helps.

http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166ydocs/jsr166y/ForkJoinTask.html

-Doug



_______________________________________________
Concurrency-interest mailing list
Concurrency-interest <at> cs.oswego.edu
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Peter Veentjer | 10 Jan 2009 20:27
Picon
Gravatar

Reducing the amount of locking

Hi All,

I'm currently playing with a heap implementation for an STM which in
essence is just a balanced tree (see Node object at the bottom of this
mail). One of the problems of building that tree is that the balancing
is quite expensive and if the number of changes is big, the system
can't process any other transactions.

So the goal is to make the period to process the transaction as short
as possible, and one of the ways to do that is to partition the tree
building, so that it can be processed in parallel and thereby reducing
the processing time:

My main question is: is there any way to reduce the amount of locking
needed in the BlockingPartitionBuilder? At the moment a single lock is
used for the placement of items and the taking of items. I have been
playing with some AtomicReferences to reduce the amount of locking,
but the system is going to be subject to deadlocks (missed signals).
So I tried this 'standard' solution first, but I'm wondering if there
is a better one.

=====================================================================

public final class ParallelSnapshotBuilder implements SnapshotBuilder {

    private final int partitionCount;
    private final PartitionBuilder[] builders;

    public ParallelSnapshotBuilder() {
        partitionCount = Runtime.getRuntime().availableProcessors();

        builders = new PartitionBuilder[partitionCount];
        for (int k = 0; k < partitionCount; k++)
            builders[k] = new BlockingPartitionBuilder();
    }

    public HeapSnapshot create(Content... changes) {
        forkBuildRoots(changes);
        Node[] roots = joinAndGetBuildRoots();
        return new PartitionedHeapSnapshot(roots);
    }

    private Node[] joinAndGetBuildRoots() {
        Node[] nodes = new Node[partitionCount];
        for (int k = 0; k < partitionCount; k++)
            nodes[k] = builders[k].joinAndGetBuildRoot();
        return nodes;
    }

    private void forkBuildRoots(Content... changes) {
        for (Content content : changes)
            getPartitionBuilder(content).forkBuildRoot(content);
    }

    private PartitionBuilder getPartitionBuilder(Content content) {
        int partition = getPartition(content);
        return builders[partition];
    }

    private int getPartition(Content content) {
        return (int) (content.getHandle() % partitionCount);
    }
}

=====================================================================

class BlockingPartitionBuilder implements PartitionBuilder {

    private final static Object TERMINATOR = new Object();

    private final Thread builderThread;

    private final Lock mainLock = new ReentrantLock();
    private final Condition contentAvailableCondition = mainLock.newCondition();
    private final Condition completedCondition = mainLock.newCondition();

    private TodoNode head;

    private volatile Node busyRoot;
    private volatile Node completedRoot;

    BlockingPartitionBuilder() {
        builderThread = new Thread(new BuildTask());
        builderThread.setDaemon(true);
        builderThread.start();
    }

    public void forkBuildRoot(Content content) {
        if (content == null) throw new NullPointerException();

        mainLock.lock();
        try {
            if (completedRoot != null) {
                busyRoot = completedRoot;
                completedRoot = null;
            }
            head = new TodoNode(head, content);
            contentAvailableCondition.signal();
        } finally {
            mainLock.unlock();
        }
    }

   public Node joinAndGetBuildRoot() {
        if (completedRoot == null) {
            mainLock.lock();
            try {
                head = new TodoNode(head, TERMINATOR);
                while (completedRoot == null)
                    completedCondition.awaitUninterruptibly();
            } finally {
                mainLock.unlock();
            }
        }
        return completedRoot;
    }

    private class BuildTask implements Runnable {

        public void run() {
            while (true)
                processItemsForSingleCommit();
        }

        private void process(Content content) {
            if (busyRoot == null)
                busyRoot = new Node(content);
            else
                busyRoot = busyRoot.createBalanced(content);
        }

        private TodoNode retrieveItems() {
            mainLock.lock();
            try {
                while (head == null)
                    contentAvailableCondition.awaitUninterruptibly();
                TodoNode result = head;
                head = null;
                return result;
            } finally {
                mainLock.unlock();
            }
        }

        private void processItemsForSingleCommit() {
            do {
                TodoNode head = retrieveItems();
                do {
                    if (head.content == TERMINATOR) {
                        mainLock.lock();
                        try {
                            completedRoot = busyRoot;
                            completedCondition.signal();
                        } finally {
                            mainLock.unlock();
                        }
                    } else {
                        process((Content) head.content);
                    }
                    head = head.next;
                } while (head != null);
            } while (completedRoot == null);
        }
    }

    private static class TodoNode {
        final TodoNode next;
        final Object content;

        TodoNode(TodoNode next, Object content) {
            this.next = next;
            this.content = content;
        }
    }
}

=====================================================================

public class Node {

    public static int height(Node node) {
        return node == null ? 0 : node.height;
    }

    private static final int COMPARE_SPOT_ON = 0;
    private static final int COMPARE_GO_RIGHT = 1;
    private static final int COMPARE_GO_LEFT = -1;

    private final Content content;
    private final Node left;
    private final Node right;
    private final int height;

    public Node(Content content) {
        this(content, null, null);
    }

    public Node(Content content, Node left, Node right) {
        this.content = content;
        this.left = left;
        this.right = right;
        this.height = max(height(left), height(right)) + 1;
    }

    public Content getContent() {
        return content;
    }

    public Node singleRotateRight() {
        if (left == null)
            throw new IllegalStateException("to do a right rotate, the
left field can't be null");

        Node q = this;
        Node p = q.left;
        Node a = p.left;
        Node b = p.right;
        Node c = q.right;

        Node qNew = new Node(q.content, b, c);
        return new Node(p.content, a, qNew);
    }

    public Node doubleRotateRight() {
        Node newLeft = left.singleRotateLeft();
        return new Node(content, newLeft, right).singleRotateRight();
    }

    public Node singleRotateLeft() {
        if (right == null)
            throw new IllegalStateException("to do a left rotate, the
right field can't be null");

        Node p = this;
        Node q = p.right;
        Node a = p.left;
        Node b = q.left;
        Node c = q.right;
        Node pNew = new Node(p.content, a, b);
        return new Node(q.content, pNew, c);
    }

    public Node doubleRotateLeft() {
        Node newRight = right.singleRotateRight();
        return new Node(content, left, newRight).singleRotateLeft();
    }

    public Node createBalanced(Content change) {
        Node unbalanced = createUnbalanced(change);
        return unbalanced.balance();
    }

    public Node balance() {
        int balanceFactor = balanceFactor();
        switch (balanceFactor) {
            case 0:
                return this;
            case 1:
                return this;
            case -1:
                return this;
            case 2:
                //het is een right/right of een right/left case
                //is the right right heavy, or left heavy
                int rightBalanceFactor = right.balanceFactor();
                if (rightBalanceFactor == 1)
                    return this.singleRotateLeft();
                else
                    return this.doubleRotateLeft();
            case -2:
                //is the left/left  heavy, or left/right heavy
                int leftBalanceFactor = left.balanceFactor();
                if (leftBalanceFactor == -1)
                    return this.singleRotateRight();
                else
                    return this.doubleRotateRight();
            default:
                throw new RuntimeException("unhandeled balanceFactor:
" + balanceFactor);
        }
    }

    public Node createUnbalanced(Content change) {
        int compare = compare(change.getHandle());
        switch (compare) {
            case COMPARE_SPOT_ON:
                //since the left and right trees are balanced, the new
node will be balanced.
                return new Node(change, left, right);
            case COMPARE_GO_RIGHT:
                Node newRight;
                if (right == null)
                    newRight = new Node(change, null, null);
                else
                    newRight = right.createBalanced(change);
                return new Node(content, left, newRight);
            case COMPARE_GO_LEFT:
                Node newLeft;
                if (left == null)
                    newLeft = new Node(change, null, null);
                else
                    newLeft = left.createBalanced(change);
                return new Node(content, newLeft, right);
            default:
                throw new RuntimeException("unhandeled compare " + compare);
        }
    }

    public int size() {
        int size = 1;
        if (right != null)
            size += right.size();
        if (left != null)
            size += left.size();
        return size;
    }

    public int balanceFactor() {
        return height(right) - height(left);
    }

    public int compare(long otherHandle) {
        if (content.getHandle() == otherHandle) {
            return COMPARE_SPOT_ON;
        } else if (content.getHandle() < otherHandle) {
            return COMPARE_GO_RIGHT;
        } else {
            return COMPARE_GO_LEFT;
        }
    }

    public Node find(long handle) {
        Node node = this;
        do {
            switch (node.compare(handle)) {
                case COMPARE_SPOT_ON:
                    return node;
                case COMPARE_GO_RIGHT:
                    node = node.right;
                    break;
                case COMPARE_GO_LEFT:
                    node = node.left;
                    break;
                default:
                    throw new RuntimeException("unhandled case");
            }
        } while (node != null);

        return null;
    }

}
Tim Peierls | 11 Jan 2009 18:45
Gravatar

Re: Reducing the amount of locking

I don't fully understand the code, so I can't answer your question directly, but it sure seems like a perfect application for map-reduce using extra166y's ParallelArray: 



With a few modifications to your Node class (providing an EMPTY Node instance and adding a mergeBalanced method that merges two balanced Nodes), your code could be as simple as this, with no locking whatsoever:

import static extra166y.Ops.Op;
import static extra166y.Ops.Reducer;
import static extra166y.ParallelArray.createUsingHandoff;
import static extra166y.ParallelArray.defaultExecutor;

public final class ParallelArraySnapshotBuilder implements SnapshotBuilder {

    public HeapSnapshot create(Content... changes) {
        Node root = createUsingHandoff(changes, defaultExecutor())
            .withMapping(contentToNode)
            .reduce(mergeBalanced, Node.EMPTY);

        return new PartitionedHeapSnapshot(new Node[] { root }); // or something more direct
    }

    private static Op<Content, Node> contentToNode = new Op<Content, Node>() {
        public Node op(Content content) { return new Node(content); }
    };

    private static Reducer<Node> mergeBalanced = new Reducer<Node>() {
        public Node op(Node a, Node b) { return a.mergeBalanced(b); }
    };
}

That aside, are you sure your use of volatile for busyRoot and completedRoot is correct? I'd worry about the places where they are tested for nullity without the lock being held. Even if it is correct, it's not easy to see that it is, which for me counts as a bug.

--tim


On Sat, Jan 10, 2009 at 2:27 PM, Peter Veentjer <alarmnummer <at> gmail.com> wrote:
Hi All,

I'm currently playing with a heap implementation for an STM which in
essence is just a balanced tree (see Node object at the bottom of this
mail). One of the problems of building that tree is that the balancing
is quite expensive and if the number of changes is big, the system
can't process any other transactions.

So the goal is to make the period to process the transaction as short
as possible, and one of the ways to do that is to partition the tree
building, so that it can be processed in parallel and thereby reducing
the processing time:

My main question is: is there any way to reduce the amount of locking
needed in the BlockingPartitionBuilder? At the moment a single lock is
used for the placement of items and the taking of items. I have been
playing with some AtomicReferences to reduce the amount of locking,
but the system is going to be subject to deadlocks (missed signals).
So I tried this 'standard' solution first, but I'm wondering if there
is a better one.

=====================================================================

public final class ParallelSnapshotBuilder implements SnapshotBuilder {

   private final int partitionCount;
   private final PartitionBuilder[] builders;

   public ParallelSnapshotBuilder() {
       partitionCount = Runtime.getRuntime().availableProcessors();

       builders = new PartitionBuilder[partitionCount];
       for (int k = 0; k < partitionCount; k++)
           builders[k] = new BlockingPartitionBuilder();
   }

   public HeapSnapshot create(Content... changes) {
       forkBuildRoots(changes);
       Node[] roots = joinAndGetBuildRoots();
       return new PartitionedHeapSnapshot(roots);
   }

   private Node[] joinAndGetBuildRoots() {
       Node[] nodes = new Node[partitionCount];
       for (int k = 0; k < partitionCount; k++)
           nodes[k] = builders[k].joinAndGetBuildRoot();
       return nodes;
   }

   private void forkBuildRoots(Content... changes) {
       for (Content content : changes)
           getPartitionBuilder(content).forkBuildRoot(content);
   }

   private PartitionBuilder getPartitionBuilder(Content content) {
       int partition = getPartition(content);
       return builders[partition];
   }

   private int getPartition(Content content) {
       return (int) (content.getHandle() % partitionCount);
   }
}

=====================================================================

class BlockingPartitionBuilder implements PartitionBuilder {

   private final static Object TERMINATOR = new Object();

   private final Thread builderThread;

   private final Lock mainLock = new ReentrantLock();
   private final Condition contentAvailableCondition = mainLock.newCondition();
   private final Condition completedCondition = mainLock.newCondition();

   private TodoNode head;

   private volatile Node busyRoot;
   private volatile Node completedRoot;

   BlockingPartitionBuilder() {
       builderThread = new Thread(new BuildTask());
       builderThread.setDaemon(true);
       builderThread.start();
   }

   public void forkBuildRoot(Content content) {
       if (content == null) throw new NullPointerException();

       mainLock.lock();
       try {
           if (completedRoot != null) {
               busyRoot = completedRoot;
               completedRoot = null;
           }
           head = new TodoNode(head, content);
           contentAvailableCondition.signal();
       } finally {
           mainLock.unlock();
       }
   }

  public Node joinAndGetBuildRoot() {
       if (completedRoot == null) {
           mainLock.lock();
           try {
               head = new TodoNode(head, TERMINATOR);
               while (completedRoot == null)
                   completedCondition.awaitUninterruptibly();
           } finally {
               mainLock.unlock();
           }
       }
       return completedRoot;
   }

   private class BuildTask implements Runnable {

       public void run() {
           while (true)
               processItemsForSingleCommit();
       }

       private void process(Content content) {
           if (busyRoot == null)
               busyRoot = new Node(content);
           else
               busyRoot = busyRoot.createBalanced(content);
       }

       private TodoNode retrieveItems() {
           mainLock.lock();
           try {
               while (head == null)
                   contentAvailableCondition.awaitUninterruptibly();
               TodoNode result = head;
               head = null;
               return result;
           } finally {
               mainLock.unlock();
           }
       }

       private void processItemsForSingleCommit() {
           do {
               TodoNode head = retrieveItems();
               do {
                   if (head.content == TERMINATOR) {
                       mainLock.lock();
                       try {
                           completedRoot = busyRoot;
                           completedCondition.signal();
                       } finally {
                           mainLock.unlock();
                       }
                   } else {
                       process((Content) head.content);
                   }
                   head = head.next;
               } while (head != null);
           } while (completedRoot == null);
       }
   }

   private static class TodoNode {
       final TodoNode next;
       final Object content;

       TodoNode(TodoNode next, Object content) {
           this.next = next;
           this.content = content;
       }
   }
}

=====================================================================

public class Node {

   public static int height(Node node) {
       return node == null ? 0 : node.height;
   }

   private static final int COMPARE_SPOT_ON = 0;
   private static final int COMPARE_GO_RIGHT = 1;
   private static final int COMPARE_GO_LEFT = -1;

   private final Content content;
   private final Node left;
   private final Node right;
   private final int height;

   public Node(Content content) {
       this(content, null, null);
   }

   public Node(Content content, Node left, Node right) {
       this.content = content;
       this.left = left;
       this.right = right;
       this.height = max(height(left), height(right)) + 1;
   }

   public Content getContent() {
       return content;
   }

   public Node singleRotateRight() {
       if (left == null)
           throw new IllegalStateException("to do a right rotate, the
left field can't be null");

       Node q = this;
       Node p = q.left;
       Node a = p.left;
       Node b = p.right;
       Node c = q.right;

       Node qNew = new Node(q.content, b, c);
       return new Node(p.content, a, qNew);
   }

   public Node doubleRotateRight() {
       Node newLeft = left.singleRotateLeft();
       return new Node(content, newLeft, right).singleRotateRight();
   }

   public Node singleRotateLeft() {
       if (right == null)
           throw new IllegalStateException("to do a left rotate, the
right field can't be null");

       Node p = this;
       Node q = p.right;
       Node a = p.left;
       Node b = q.left;
       Node c = q.right;
       Node pNew = new Node(p.content, a, b);
       return new Node(q.content, pNew, c);
   }

   public Node doubleRotateLeft() {
       Node newRight = right.singleRotateRight();
       return new Node(content, left, newRight).singleRotateLeft();
   }

   public Node createBalanced(Content change) {
       Node unbalanced = createUnbalanced(change);
       return unbalanced.balance();
   }

   public Node balance() {
       int balanceFactor = balanceFactor();
       switch (balanceFactor) {
           case 0:
               return this;
           case 1:
               return this;
           case -1:
               return this;
           case 2:
               //het is een right/right of een right/left case
               //is the right right heavy, or left heavy
               int rightBalanceFactor = right.balanceFactor();
               if (rightBalanceFactor == 1)
                   return this.singleRotateLeft();
               else
                   return this.doubleRotateLeft();
           case -2:
               //is the left/left  heavy, or left/right heavy
               int leftBalanceFactor = left.balanceFactor();
               if (leftBalanceFactor == -1)
                   return this.singleRotateRight();
               else
                   return this.doubleRotateRight();
           default:
               throw new RuntimeException("unhandeled balanceFactor:
" + balanceFactor);
       }
   }

   public Node createUnbalanced(Content change) {
       int compare = compare(change.getHandle());
       switch (compare) {
           case COMPARE_SPOT_ON:
               //since the left and right trees are balanced, the new
node will be balanced.
               return new Node(change, left, right);
           case COMPARE_GO_RIGHT:
               Node newRight;
               if (right == null)
                   newRight = new Node(change, null, null);
               else
                   newRight = right.createBalanced(change);
               return new Node(content, left, newRight);
           case COMPARE_GO_LEFT:
               Node newLeft;
               if (left == null)
                   newLeft = new Node(change, null, null);
               else
                   newLeft = left.createBalanced(change);
               return new Node(content, newLeft, right);
           default:
               throw new RuntimeException("unhandeled compare " + compare);
       }
   }

   public int size() {
       int size = 1;
       if (right != null)
           size += right.size();
       if (left != null)
           size += left.size();
       return size;
   }

   public int balanceFactor() {
       return height(right) - height(left);
   }

   public int compare(long otherHandle) {
       if (content.getHandle() == otherHandle) {
           return COMPARE_SPOT_ON;
       } else if (content.getHandle() < otherHandle) {
           return COMPARE_GO_RIGHT;
       } else {
           return COMPARE_GO_LEFT;
       }
   }

   public Node find(long handle) {
       Node node = this;
       do {
           switch (node.compare(handle)) {
               case COMPARE_SPOT_ON:
                   return node;
               case COMPARE_GO_RIGHT:
                   node = node.right;
                   break;
               case COMPARE_GO_LEFT:
                   node = node.left;
                   break;
               default:
                   throw new RuntimeException("unhandled case");
           }
       } while (node != null);

       return null;
   }

}
_______________________________________________
Concurrency-interest mailing list
Concurrency-interest <at> cs.oswego.edu
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
Concurrency-interest <at> cs.oswego.edu
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Doug Lea | 12 Jan 2009 18:31
Favicon

ThreadLocalRandom


As probably the final refactoring pass on Java7 versions of ForkJoin etc
the thread-local random generator was pulled out into a stand-alone class.
Class ThreadLocalRandom is useful in most situations where people use
java.util.Random across multiple threads. It is a subclass of Random,
but has no constructor -- instead a static "current()" method to
get the one for the current thread. It also doesn't let you change
the seed. (So people who need thread-local generators with explicit
seed control can't use it.)

The main reason for using it is performance, including performance
testing. Using a contended shared Random will often be 10X slower,
and mask the performance differences you are actually looking for.
(Some SPEC benchmarks have had this problem.)

See:
http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166ydocs/jsr166y/ThreadLocalRandom.html

Comments welcome.

Also, as we move closer to jdk7 (openjdk) integration,
anyone wanting to help with code or documentation reviews
ot testing might want to take a look. See links from
http://gee.cs.oswego.edu/dl/concurrency-interest/index.html

-Doug

Gmane