This commit is contained in:
Michael McMahon 2011-01-13 11:10:14 +00:00
commit 7558885d92
77 changed files with 3528 additions and 1948 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -133,27 +133,60 @@ set_event_notification(jvmtiEventMode mode, EventIndex ei)
return error; return error;
} }
typedef struct {
int major;
int minor;
} version_type;
typedef struct {
version_type runtime;
version_type compiletime;
} compatible_versions_type;
/*
* List of explicitly compatible JVMTI versions, specified as
* { runtime version, compile-time version } pairs. -1 is a wildcard.
*/
static int nof_compatible_versions = 3;
static compatible_versions_type compatible_versions_list[] = {
/*
* FIXUP: Allow version 0 to be compatible with anything
* Special check for FCS of 1.0.
*/
{ { 0, -1 }, { -1, -1 } },
{ { -1, -1 }, { 0, -1 } },
/*
* 1.2 is runtime compatible with 1.1 -- just make sure to check the
* version before using any new 1.2 features
*/
{ { 1, 1 }, { 1, 2 } }
};
/* Logic to determine JVMTI version compatibility */ /* Logic to determine JVMTI version compatibility */
static jboolean static jboolean
compatible_versions(jint major_runtime, jint minor_runtime, compatible_versions(jint major_runtime, jint minor_runtime,
jint major_compiletime, jint minor_compiletime) jint major_compiletime, jint minor_compiletime)
{ {
#if 1 /* FIXUP: We allow version 0 to be compatible with anything */ /*
/* Special check for FCS of 1.0. */ * First check to see if versions are explicitly compatible via the
if ( major_runtime == 0 || major_compiletime == 0 ) { * list specified above.
return JNI_TRUE; */
int i;
for (i = 0; i < nof_compatible_versions; ++i) {
version_type runtime = compatible_versions_list[i].runtime;
version_type comptime = compatible_versions_list[i].compiletime;
if ((major_runtime == runtime.major || runtime.major == -1) &&
(minor_runtime == runtime.minor || runtime.minor == -1) &&
(major_compiletime == comptime.major || comptime.major == -1) &&
(minor_compiletime == comptime.minor || comptime.minor == -1)) {
return JNI_TRUE;
}
} }
#endif
/* Runtime major version must match. */ return major_runtime == major_compiletime &&
if ( major_runtime != major_compiletime ) { minor_runtime >= minor_compiletime;
return JNI_FALSE;
}
/* Runtime minor version must be >= the version compiled with. */
if ( minor_runtime < minor_compiletime ) {
return JNI_FALSE;
}
/* Assumed compatible */
return JNI_TRUE;
} }
/* OnLoad startup: /* OnLoad startup:

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -39,6 +39,7 @@
#include "stepControl.h" #include "stepControl.h"
#include "threadControl.h" #include "threadControl.h"
#include "SDE.h" #include "SDE.h"
#include "jvmti.h"
typedef struct ClassFilter { typedef struct ClassFilter {
jclass clazz; jclass clazz;
@ -275,6 +276,24 @@ patternStringMatch(char *classname, const char *pattern)
} }
} }
static jboolean isVersionGte12x() {
jint version;
jvmtiError err =
JVMTI_FUNC_PTR(gdata->jvmti,GetVersionNumber)(gdata->jvmti, &version);
if (err == JVMTI_ERROR_NONE) {
jint major, minor;
major = (version & JVMTI_VERSION_MASK_MAJOR)
>> JVMTI_VERSION_SHIFT_MAJOR;
minor = (version & JVMTI_VERSION_MASK_MINOR)
>> JVMTI_VERSION_SHIFT_MINOR;
return (major > 1 || major == 1 && minor >= 2);
} else {
return JNI_FALSE;
}
}
/* Return the object instance in which the event occurred */ /* Return the object instance in which the event occurred */
/* Return NULL if static or if an error occurs */ /* Return NULL if static or if an error occurs */
static jobject static jobject
@ -286,6 +305,14 @@ eventInstance(EventInfo *evinfo)
jint modifiers = 0; jint modifiers = 0;
jvmtiError error; jvmtiError error;
static jboolean got_version = JNI_FALSE;
static jboolean is_version_gte_12x = JNI_FALSE;
if (!got_version) {
is_version_gte_12x = isVersionGte12x();
got_version = JNI_TRUE;
}
switch (evinfo->ei) { switch (evinfo->ei) {
case EI_SINGLE_STEP: case EI_SINGLE_STEP:
case EI_BREAKPOINT: case EI_BREAKPOINT:
@ -314,11 +341,18 @@ eventInstance(EventInfo *evinfo)
/* fail if error or static (0x8) */ /* fail if error or static (0x8) */
if (error == JVMTI_ERROR_NONE && thread!=NULL && (modifiers & 0x8) == 0) { if (error == JVMTI_ERROR_NONE && thread!=NULL && (modifiers & 0x8) == 0) {
FrameNumber fnum = 0; FrameNumber fnum = 0;
/* get slot zero object "this" */ if (is_version_gte_12x) {
error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject) /* Use new 1.2.x function, GetLocalInstance */
(gdata->jvmti, thread, fnum, 0, &object); error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInstance)
if (error != JVMTI_ERROR_NONE) (gdata->jvmti, thread, fnum, &object);
} else {
/* get slot zero object "this" */
error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
(gdata->jvmti, thread, fnum, 0, &object);
}
if (error != JVMTI_ERROR_NONE) {
object = NULL; object = NULL;
}
} }
return object; return object;

View File

@ -1704,7 +1704,7 @@ class BandStructure {
for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) { for (int i = 0; i < ATTR_CONTEXT_LIMIT; i++) {
assert(attrIndexLimit[i] == 0); assert(attrIndexLimit[i] == 0);
attrIndexLimit[i] = 32; // just for the sake of predefs. attrIndexLimit[i] = 32; // just for the sake of predefs.
attrDefs.set(i, new ArrayList<>(Collections.nCopies( attrDefs.set(i, new ArrayList<Attribute.Layout>(Collections.nCopies(
attrIndexLimit[i], (Attribute.Layout)null))); attrIndexLimit[i], (Attribute.Layout)null)));
} }

View File

@ -329,7 +329,7 @@ public class ObjectStreamClass implements Serializable {
entry = th; entry = th;
} }
if (future.set(entry)) { if (future.set(entry)) {
Caches.localDescs.put(key, new SoftReference<>(entry)); Caches.localDescs.put(key, new SoftReference<Object>(entry));
} else { } else {
// nested lookup call already set future // nested lookup call already set future
entry = future.get(); entry = future.get();
@ -2118,7 +2118,7 @@ public class ObjectStreamClass implements Serializable {
entry = th; entry = th;
} }
future.set(entry); future.set(entry);
Caches.reflectors.put(key, new SoftReference<>(entry)); Caches.reflectors.put(key, new SoftReference<Object>(entry));
} }
if (entry instanceof FieldReflector) { if (entry instanceof FieldReflector) {

View File

@ -67,7 +67,7 @@ class StringCoding {
} }
private static <T> void set(ThreadLocal<SoftReference<T>> tl, T ob) { private static <T> void set(ThreadLocal<SoftReference<T>> tl, T ob) {
tl.set(new SoftReference<>(ob)); tl.set(new SoftReference<T>(ob));
} }
// Trim the given byte array to the given length // Trim the given byte array to the given length

View File

@ -473,7 +473,9 @@ public class Timestamp extends java.util.Date {
* @since 1.4 * @since 1.4
*/ */
public int compareTo(Timestamp ts) { public int compareTo(Timestamp ts) {
int i = super.compareTo(ts); long thisTime = this.getTime();
long anotherTime = ts.getTime();
int i = (thisTime<anotherTime ? -1 :(thisTime==anotherTime?0 :1));
if (i == 0) { if (i == 0) {
if (nanos > ts.nanos) { if (nanos > ts.nanos) {
return 1; return 1;

View File

@ -1452,10 +1452,10 @@ public class Collections {
* when o is a Map.Entry, and calls o.setValue. * when o is a Map.Entry, and calls o.setValue.
*/ */
public boolean containsAll(Collection<?> coll) { public boolean containsAll(Collection<?> coll) {
Iterator<?> it = coll.iterator(); for (Object e : coll) {
while (it.hasNext()) if (!contains(e)) // Invokes safe contains() above
if (!contains(it.next())) // Invokes safe contains() above
return false; return false;
}
return true; return true;
} }
public boolean equals(Object o) { public boolean equals(Object o) {

View File

@ -26,9 +26,9 @@
package java.util; package java.util;
/** /**
* Linked list implementation of the {@link List} and {@link Deque} interfaces. * Doubly-linked list implementation of the {@code List} and {@code Deque}
* Implements all optional operations, and permits all elements (including * interfaces. Implements all optional list operations, and permits all
* {@code null}). * elements (including {@code null}).
* *
* <p>All of the operations perform as could be expected for a doubly-linked * <p>All of the operations perform as could be expected for a doubly-linked
* list. Operations that index into the list will traverse the list from * list. Operations that index into the list will traverse the list from
@ -249,7 +249,7 @@ public class LinkedList<E>
* @return the last element in this list * @return the last element in this list
* @throws NoSuchElementException if this list is empty * @throws NoSuchElementException if this list is empty
*/ */
public E getLast() { public E getLast() {
final Node<E> l = last; final Node<E> l = last;
if (l == null) if (l == null)
throw new NoSuchElementException(); throw new NoSuchElementException();

View File

@ -49,14 +49,14 @@ import java.util.*;
* <p>This is a classic &quot;bounded buffer&quot;, in which a * <p>This is a classic &quot;bounded buffer&quot;, in which a
* fixed-sized array holds elements inserted by producers and * fixed-sized array holds elements inserted by producers and
* extracted by consumers. Once created, the capacity cannot be * extracted by consumers. Once created, the capacity cannot be
* increased. Attempts to <tt>put</tt> an element into a full queue * changed. Attempts to {@code put} an element into a full queue
* will result in the operation blocking; attempts to <tt>take</tt> an * will result in the operation blocking; attempts to {@code take} an
* element from an empty queue will similarly block. * element from an empty queue will similarly block.
* *
* <p> This class supports an optional fairness policy for ordering * <p>This class supports an optional fairness policy for ordering
* waiting producer and consumer threads. By default, this ordering * waiting producer and consumer threads. By default, this ordering
* is not guaranteed. However, a queue constructed with fairness set * is not guaranteed. However, a queue constructed with fairness set
* to <tt>true</tt> grants threads access in FIFO order. Fairness * to {@code true} grants threads access in FIFO order. Fairness
* generally decreases throughput but reduces variability and avoids * generally decreases throughput but reduces variability and avoids
* starvation. * starvation.
* *
@ -83,14 +83,17 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
*/ */
private static final long serialVersionUID = -817911632652898426L; private static final long serialVersionUID = -817911632652898426L;
/** The queued items */ /** The queued items */
private final E[] items; final Object[] items;
/** items index for next take, poll or remove */
private int takeIndex; /** items index for next take, poll, peek or remove */
/** items index for next put, offer, or add. */ int takeIndex;
private int putIndex;
/** Number of items in the queue */ /** items index for next put, offer, or add */
private int count; int putIndex;
/** Number of elements in the queue */
int count;
/* /*
* Concurrency control uses the classic two-condition algorithm * Concurrency control uses the classic two-condition algorithm
@ -98,7 +101,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
*/ */
/** Main lock guarding all access */ /** Main lock guarding all access */
private final ReentrantLock lock; final ReentrantLock lock;
/** Condition for waiting takes */ /** Condition for waiting takes */
private final Condition notEmpty; private final Condition notEmpty;
/** Condition for waiting puts */ /** Condition for waiting puts */
@ -110,7 +113,36 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* Circularly increment i. * Circularly increment i.
*/ */
final int inc(int i) { final int inc(int i) {
return (++i == items.length)? 0 : i; return (++i == items.length) ? 0 : i;
}
/**
* Circularly decrement i.
*/
final int dec(int i) {
return ((i == 0) ? items.length : i) - 1;
}
@SuppressWarnings("unchecked")
static <E> E cast(Object item) {
return (E) item;
}
/**
* Returns item at index i.
*/
final E itemAt(int i) {
return this.<E>cast(items[i]);
}
/**
* Throws NullPointerException if argument is null.
*
* @param v the element
*/
private static void checkNotNull(Object v) {
if (v == null)
throw new NullPointerException();
} }
/** /**
@ -129,8 +161,8 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* Call only when holding lock. * Call only when holding lock.
*/ */
private E extract() { private E extract() {
final E[] items = this.items; final Object[] items = this.items;
E x = items[takeIndex]; E x = this.<E>cast(items[takeIndex]);
items[takeIndex] = null; items[takeIndex] = null;
takeIndex = inc(takeIndex); takeIndex = inc(takeIndex);
--count; --count;
@ -139,11 +171,12 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
} }
/** /**
* Utility for remove and iterator.remove: Delete item at position i. * Deletes item at position i.
* Utility for remove and iterator.remove.
* Call only when holding lock. * Call only when holding lock.
*/ */
void removeAt(int i) { void removeAt(int i) {
final E[] items = this.items; final Object[] items = this.items;
// if removing front item, just advance // if removing front item, just advance
if (i == takeIndex) { if (i == takeIndex) {
items[takeIndex] = null; items[takeIndex] = null;
@ -167,69 +200,82 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
} }
/** /**
* Creates an <tt>ArrayBlockingQueue</tt> with the given (fixed) * Creates an {@code ArrayBlockingQueue} with the given (fixed)
* capacity and default access policy. * capacity and default access policy.
* *
* @param capacity the capacity of this queue * @param capacity the capacity of this queue
* @throws IllegalArgumentException if <tt>capacity</tt> is less than 1 * @throws IllegalArgumentException if {@code capacity < 1}
*/ */
public ArrayBlockingQueue(int capacity) { public ArrayBlockingQueue(int capacity) {
this(capacity, false); this(capacity, false);
} }
/** /**
* Creates an <tt>ArrayBlockingQueue</tt> with the given (fixed) * Creates an {@code ArrayBlockingQueue} with the given (fixed)
* capacity and the specified access policy. * capacity and the specified access policy.
* *
* @param capacity the capacity of this queue * @param capacity the capacity of this queue
* @param fair if <tt>true</tt> then queue accesses for threads blocked * @param fair if {@code true} then queue accesses for threads blocked
* on insertion or removal, are processed in FIFO order; * on insertion or removal, are processed in FIFO order;
* if <tt>false</tt> the access order is unspecified. * if {@code false} the access order is unspecified.
* @throws IllegalArgumentException if <tt>capacity</tt> is less than 1 * @throws IllegalArgumentException if {@code capacity < 1}
*/ */
public ArrayBlockingQueue(int capacity, boolean fair) { public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0) if (capacity <= 0)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
this.items = (E[]) new Object[capacity]; this.items = new Object[capacity];
lock = new ReentrantLock(fair); lock = new ReentrantLock(fair);
notEmpty = lock.newCondition(); notEmpty = lock.newCondition();
notFull = lock.newCondition(); notFull = lock.newCondition();
} }
/** /**
* Creates an <tt>ArrayBlockingQueue</tt> with the given (fixed) * Creates an {@code ArrayBlockingQueue} with the given (fixed)
* capacity, the specified access policy and initially containing the * capacity, the specified access policy and initially containing the
* elements of the given collection, * elements of the given collection,
* added in traversal order of the collection's iterator. * added in traversal order of the collection's iterator.
* *
* @param capacity the capacity of this queue * @param capacity the capacity of this queue
* @param fair if <tt>true</tt> then queue accesses for threads blocked * @param fair if {@code true} then queue accesses for threads blocked
* on insertion or removal, are processed in FIFO order; * on insertion or removal, are processed in FIFO order;
* if <tt>false</tt> the access order is unspecified. * if {@code false} the access order is unspecified.
* @param c the collection of elements to initially contain * @param c the collection of elements to initially contain
* @throws IllegalArgumentException if <tt>capacity</tt> is less than * @throws IllegalArgumentException if {@code capacity} is less than
* <tt>c.size()</tt>, or less than 1. * {@code c.size()}, or less than 1.
* @throws NullPointerException if the specified collection or any * @throws NullPointerException if the specified collection or any
* of its elements are null * of its elements are null
*/ */
public ArrayBlockingQueue(int capacity, boolean fair, public ArrayBlockingQueue(int capacity, boolean fair,
Collection<? extends E> c) { Collection<? extends E> c) {
this(capacity, fair); this(capacity, fair);
if (capacity < c.size())
throw new IllegalArgumentException();
for (E e : c) final ReentrantLock lock = this.lock;
add(e); lock.lock(); // Lock only for visibility, not mutual exclusion
try {
int i = 0;
try {
for (E e : c) {
checkNotNull(e);
items[i++] = e;
}
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
count = i;
putIndex = (i == capacity) ? 0 : i;
} finally {
lock.unlock();
}
} }
/** /**
* Inserts the specified element at the tail of this queue if it is * Inserts the specified element at the tail of this queue if it is
* possible to do so immediately without exceeding the queue's capacity, * possible to do so immediately without exceeding the queue's capacity,
* returning <tt>true</tt> upon success and throwing an * returning {@code true} upon success and throwing an
* <tt>IllegalStateException</tt> if this queue is full. * {@code IllegalStateException} if this queue is full.
* *
* @param e the element to add * @param e the element to add
* @return <tt>true</tt> (as specified by {@link Collection#add}) * @return {@code true} (as specified by {@link Collection#add})
* @throws IllegalStateException if this queue is full * @throws IllegalStateException if this queue is full
* @throws NullPointerException if the specified element is null * @throws NullPointerException if the specified element is null
*/ */
@ -240,14 +286,14 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
/** /**
* Inserts the specified element at the tail of this queue if it is * Inserts the specified element at the tail of this queue if it is
* possible to do so immediately without exceeding the queue's capacity, * possible to do so immediately without exceeding the queue's capacity,
* returning <tt>true</tt> upon success and <tt>false</tt> if this queue * returning {@code true} upon success and {@code false} if this queue
* is full. This method is generally preferable to method {@link #add}, * is full. This method is generally preferable to method {@link #add},
* which can fail to insert an element only by throwing an exception. * which can fail to insert an element only by throwing an exception.
* *
* @throws NullPointerException if the specified element is null * @throws NullPointerException if the specified element is null
*/ */
public boolean offer(E e) { public boolean offer(E e) {
if (e == null) throw new NullPointerException(); checkNotNull(e);
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
@ -270,18 +316,12 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* @throws NullPointerException {@inheritDoc} * @throws NullPointerException {@inheritDoc}
*/ */
public void put(E e) throws InterruptedException { public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException(); checkNotNull(e);
final E[] items = this.items;
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lockInterruptibly(); lock.lockInterruptibly();
try { try {
try { while (count == items.length)
while (count == items.length) notFull.await();
notFull.await();
} catch (InterruptedException ie) {
notFull.signal(); // propagate to non-interrupted thread
throw ie;
}
insert(e); insert(e);
} finally { } finally {
lock.unlock(); lock.unlock();
@ -299,25 +339,18 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
public boolean offer(E e, long timeout, TimeUnit unit) public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException { throws InterruptedException {
if (e == null) throw new NullPointerException(); checkNotNull(e);
long nanos = unit.toNanos(timeout); long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lockInterruptibly(); lock.lockInterruptibly();
try { try {
for (;;) { while (count == items.length) {
if (count != items.length) {
insert(e);
return true;
}
if (nanos <= 0) if (nanos <= 0)
return false; return false;
try { nanos = notFull.awaitNanos(nanos);
nanos = notFull.awaitNanos(nanos);
} catch (InterruptedException ie) {
notFull.signal(); // propagate to non-interrupted thread
throw ie;
}
} }
insert(e);
return true;
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@ -327,10 +360,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
if (count == 0) return (count == 0) ? null : extract();
return null;
E x = extract();
return x;
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@ -340,15 +370,9 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lockInterruptibly(); lock.lockInterruptibly();
try { try {
try { while (count == 0)
while (count == 0) notEmpty.await();
notEmpty.await(); return extract();
} catch (InterruptedException ie) {
notEmpty.signal(); // propagate to non-interrupted thread
throw ie;
}
E x = extract();
return x;
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@ -359,21 +383,12 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lockInterruptibly(); lock.lockInterruptibly();
try { try {
for (;;) { while (count == 0) {
if (count != 0) {
E x = extract();
return x;
}
if (nanos <= 0) if (nanos <= 0)
return null; return null;
try { nanos = notEmpty.awaitNanos(nanos);
nanos = notEmpty.awaitNanos(nanos);
} catch (InterruptedException ie) {
notEmpty.signal(); // propagate to non-interrupted thread
throw ie;
}
} }
return extract();
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@ -383,7 +398,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
return (count == 0) ? null : items[takeIndex]; return (count == 0) ? null : itemAt(takeIndex);
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@ -412,10 +427,10 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* Returns the number of additional elements that this queue can ideally * Returns the number of additional elements that this queue can ideally
* (in the absence of memory or resource constraints) accept without * (in the absence of memory or resource constraints) accept without
* blocking. This is always equal to the initial capacity of this queue * blocking. This is always equal to the initial capacity of this queue
* less the current <tt>size</tt> of this queue. * less the current {@code size} of this queue.
* *
* <p>Note that you <em>cannot</em> always tell if an attempt to insert * <p>Note that you <em>cannot</em> always tell if an attempt to insert
* an element will succeed by inspecting <tt>remainingCapacity</tt> * an element will succeed by inspecting {@code remainingCapacity}
* because it may be the case that another thread is about to * because it may be the case that another thread is about to
* insert or remove an element. * insert or remove an element.
*/ */
@ -431,59 +446,56 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
/** /**
* Removes a single instance of the specified element from this queue, * Removes a single instance of the specified element from this queue,
* if it is present. More formally, removes an element <tt>e</tt> such * if it is present. More formally, removes an element {@code e} such
* that <tt>o.equals(e)</tt>, if this queue contains one or more such * that {@code o.equals(e)}, if this queue contains one or more such
* elements. * elements.
* Returns <tt>true</tt> if this queue contained the specified element * Returns {@code true} if this queue contained the specified element
* (or equivalently, if this queue changed as a result of the call). * (or equivalently, if this queue changed as a result of the call).
* *
* <p>Removal of interior elements in circular array based queues
* is an intrinsically slow and disruptive operation, so should
* be undertaken only in exceptional circumstances, ideally
* only when the queue is known not to be accessible by other
* threads.
*
* @param o element to be removed from this queue, if present * @param o element to be removed from this queue, if present
* @return <tt>true</tt> if this queue changed as a result of the call * @return {@code true} if this queue changed as a result of the call
*/ */
public boolean remove(Object o) { public boolean remove(Object o) {
if (o == null) return false; if (o == null) return false;
final E[] items = this.items; final Object[] items = this.items;
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
int i = takeIndex; for (int i = takeIndex, k = count; k > 0; i = inc(i), k--) {
int k = 0;
for (;;) {
if (k++ >= count)
return false;
if (o.equals(items[i])) { if (o.equals(items[i])) {
removeAt(i); removeAt(i);
return true; return true;
} }
i = inc(i);
} }
return false;
} finally { } finally {
lock.unlock(); lock.unlock();
} }
} }
/** /**
* Returns <tt>true</tt> if this queue contains the specified element. * Returns {@code true} if this queue contains the specified element.
* More formally, returns <tt>true</tt> if and only if this queue contains * More formally, returns {@code true} if and only if this queue contains
* at least one element <tt>e</tt> such that <tt>o.equals(e)</tt>. * at least one element {@code e} such that {@code o.equals(e)}.
* *
* @param o object to be checked for containment in this queue * @param o object to be checked for containment in this queue
* @return <tt>true</tt> if this queue contains the specified element * @return {@code true} if this queue contains the specified element
*/ */
public boolean contains(Object o) { public boolean contains(Object o) {
if (o == null) return false; if (o == null) return false;
final E[] items = this.items; final Object[] items = this.items;
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
int i = takeIndex; for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)
int k = 0;
while (k++ < count) {
if (o.equals(items[i])) if (o.equals(items[i]))
return true; return true;
i = inc(i);
}
return false; return false;
} finally { } finally {
lock.unlock(); lock.unlock();
@ -504,17 +516,14 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* @return an array containing all of the elements in this queue * @return an array containing all of the elements in this queue
*/ */
public Object[] toArray() { public Object[] toArray() {
final E[] items = this.items; final Object[] items = this.items;
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
final int count = this.count;
Object[] a = new Object[count]; Object[] a = new Object[count];
int k = 0; for (int i = takeIndex, k = 0; k < count; i = inc(i), k++)
int i = takeIndex; a[k] = items[i];
while (k < count) {
a[k++] = items[i];
i = inc(i);
}
return a; return a;
} finally { } finally {
lock.unlock(); lock.unlock();
@ -531,22 +540,22 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* <p>If this queue fits in the specified array with room to spare * <p>If this queue fits in the specified array with room to spare
* (i.e., the array has more elements than this queue), the element in * (i.e., the array has more elements than this queue), the element in
* the array immediately following the end of the queue is set to * the array immediately following the end of the queue is set to
* <tt>null</tt>. * {@code null}.
* *
* <p>Like the {@link #toArray()} method, this method acts as bridge between * <p>Like the {@link #toArray()} method, this method acts as bridge between
* array-based and collection-based APIs. Further, this method allows * array-based and collection-based APIs. Further, this method allows
* precise control over the runtime type of the output array, and may, * precise control over the runtime type of the output array, and may,
* under certain circumstances, be used to save allocation costs. * under certain circumstances, be used to save allocation costs.
* *
* <p>Suppose <tt>x</tt> is a queue known to contain only strings. * <p>Suppose {@code x} is a queue known to contain only strings.
* The following code can be used to dump the queue into a newly * The following code can be used to dump the queue into a newly
* allocated array of <tt>String</tt>: * allocated array of {@code String}:
* *
* <pre> * <pre>
* String[] y = x.toArray(new String[0]);</pre> * String[] y = x.toArray(new String[0]);</pre>
* *
* Note that <tt>toArray(new Object[0])</tt> is identical in function to * Note that {@code toArray(new Object[0])} is identical in function to
* <tt>toArray()</tt>. * {@code toArray()}.
* *
* @param a the array into which the elements of the queue are to * @param a the array into which the elements of the queue are to
* be stored, if it is big enough; otherwise, a new array of the * be stored, if it is big enough; otherwise, a new array of the
@ -557,24 +566,20 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* this queue * this queue
* @throws NullPointerException if the specified array is null * @throws NullPointerException if the specified array is null
*/ */
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) { public <T> T[] toArray(T[] a) {
final E[] items = this.items; final Object[] items = this.items;
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
if (a.length < count) final int count = this.count;
final int len = a.length;
if (len < count)
a = (T[])java.lang.reflect.Array.newInstance( a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), a.getClass().getComponentType(), count);
count for (int i = takeIndex, k = 0; k < count; i = inc(i), k++)
); a[k] = (T) items[i];
if (len > count)
int k = 0;
int i = takeIndex;
while (k < count) {
a[k++] = (T)items[i];
i = inc(i);
}
if (a.length > count)
a[count] = null; a[count] = null;
return a; return a;
} finally { } finally {
@ -586,7 +591,19 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
return super.toString(); int k = count;
if (k == 0)
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (int i = takeIndex; ; i = inc(i)) {
Object e = items[i];
sb.append(e == this ? "(this Collection)" : e);
if (--k == 0)
return sb.append(']').toString();
sb.append(',').append(' ');
}
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@ -597,16 +614,12 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* The queue will be empty after this call returns. * The queue will be empty after this call returns.
*/ */
public void clear() { public void clear() {
final E[] items = this.items; final Object[] items = this.items;
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
int i = takeIndex; for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)
int k = count;
while (k-- > 0) {
items[i] = null; items[i] = null;
i = inc(i);
}
count = 0; count = 0;
putIndex = 0; putIndex = 0;
takeIndex = 0; takeIndex = 0;
@ -623,11 +636,10 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* @throws IllegalArgumentException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc}
*/ */
public int drainTo(Collection<? super E> c) { public int drainTo(Collection<? super E> c) {
if (c == null) checkNotNull(c);
throw new NullPointerException();
if (c == this) if (c == this)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
final E[] items = this.items; final Object[] items = this.items;
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
@ -635,7 +647,7 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
int n = 0; int n = 0;
int max = count; int max = count;
while (n < max) { while (n < max) {
c.add(items[i]); c.add(this.<E>cast(items[i]));
items[i] = null; items[i] = null;
i = inc(i); i = inc(i);
++n; ++n;
@ -659,22 +671,20 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* @throws IllegalArgumentException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc}
*/ */
public int drainTo(Collection<? super E> c, int maxElements) { public int drainTo(Collection<? super E> c, int maxElements) {
if (c == null) checkNotNull(c);
throw new NullPointerException();
if (c == this) if (c == this)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
if (maxElements <= 0) if (maxElements <= 0)
return 0; return 0;
final E[] items = this.items; final Object[] items = this.items;
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
int i = takeIndex; int i = takeIndex;
int n = 0; int n = 0;
int sz = count; int max = (maxElements < count) ? maxElements : count;
int max = (maxElements < count)? maxElements : count;
while (n < max) { while (n < max) {
c.add(items[i]); c.add(this.<E>cast(items[i]));
items[i] = null; items[i] = null;
i = inc(i); i = inc(i);
++n; ++n;
@ -690,11 +700,13 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
} }
} }
/** /**
* Returns an iterator over the elements in this queue in proper sequence. * Returns an iterator over the elements in this queue in proper sequence.
* The returned <tt>Iterator</tt> is a "weakly consistent" iterator that * The elements will be returned in order from first (head) to last (tail).
* will never throw {@link ConcurrentModificationException}, *
* <p>The returned {@code Iterator} is a "weakly consistent" iterator that
* will never throw {@link java.util.ConcurrentModificationException
* ConcurrentModificationException},
* and guarantees to traverse elements as they existed upon * and guarantees to traverse elements as they existed upon
* construction of the iterator, and may (but is not guaranteed to) * construction of the iterator, and may (but is not guaranteed to)
* reflect any modifications subsequent to construction. * reflect any modifications subsequent to construction.
@ -702,83 +714,65 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
* @return an iterator over the elements in this queue in proper sequence * @return an iterator over the elements in this queue in proper sequence
*/ */
public Iterator<E> iterator() { public Iterator<E> iterator() {
final ReentrantLock lock = this.lock; return new Itr();
lock.lock();
try {
return new Itr();
} finally {
lock.unlock();
}
} }
/** /**
* Iterator for ArrayBlockingQueue * Iterator for ArrayBlockingQueue. To maintain weak consistency
* with respect to puts and takes, we (1) read ahead one slot, so
* as to not report hasNext true but then not have an element to
* return -- however we later recheck this slot to use the most
* current value; (2) ensure that each array slot is traversed at
* most once (by tracking "remaining" elements); (3) skip over
* null slots, which can occur if takes race ahead of iterators.
* However, for circular array-based queues, we cannot rely on any
* well established definition of what it means to be weakly
* consistent with respect to interior removes since these may
* require slot overwrites in the process of sliding elements to
* cover gaps. So we settle for resiliency, operating on
* established apparent nexts, which may miss some elements that
* have moved between calls to next.
*/ */
private class Itr implements Iterator<E> { private class Itr implements Iterator<E> {
/** private int remaining; // Number of elements yet to be returned
* Index of element to be returned by next, private int nextIndex; // Index of element to be returned by next
* or a negative number if no such. private E nextItem; // Element to be returned by next call to next
*/ private E lastItem; // Element returned by last call to next
private int nextIndex; private int lastRet; // Index of last element returned, or -1 if none
/**
* nextItem holds on to item fields because once we claim
* that an element exists in hasNext(), we must return it in
* the following next() call even if it was in the process of
* being removed when hasNext() was called.
*/
private E nextItem;
/**
* Index of element returned by most recent call to next.
* Reset to -1 if this element is deleted by a call to remove.
*/
private int lastRet;
Itr() { Itr() {
lastRet = -1; final ReentrantLock lock = ArrayBlockingQueue.this.lock;
if (count == 0) lock.lock();
nextIndex = -1; try {
else { lastRet = -1;
nextIndex = takeIndex; if ((remaining = count) > 0)
nextItem = items[takeIndex]; nextItem = itemAt(nextIndex = takeIndex);
} finally {
lock.unlock();
} }
} }
public boolean hasNext() { public boolean hasNext() {
/* return remaining > 0;
* No sync. We can return true by mistake here
* only if this iterator passed across threads,
* which we don't support anyway.
*/
return nextIndex >= 0;
}
/**
* Checks whether nextIndex is valid; if so setting nextItem.
* Stops iterator when either hits putIndex or sees null item.
*/
private void checkNext() {
if (nextIndex == putIndex) {
nextIndex = -1;
nextItem = null;
} else {
nextItem = items[nextIndex];
if (nextItem == null)
nextIndex = -1;
}
} }
public E next() { public E next() {
final ReentrantLock lock = ArrayBlockingQueue.this.lock; final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock(); lock.lock();
try { try {
if (nextIndex < 0) if (remaining <= 0)
throw new NoSuchElementException(); throw new NoSuchElementException();
lastRet = nextIndex; lastRet = nextIndex;
E x = nextItem; E x = itemAt(nextIndex); // check for fresher value
nextIndex = inc(nextIndex); if (x == null) {
checkNext(); x = nextItem; // we are forced to report old value
lastItem = null; // but ensure remove fails
}
else
lastItem = x;
while (--remaining > 0 && // skip over nulls
(nextItem = itemAt(nextIndex = inc(nextIndex))) == null)
;
return x; return x;
} finally { } finally {
lock.unlock(); lock.unlock();
@ -793,15 +787,19 @@ public class ArrayBlockingQueue<E> extends AbstractQueue<E>
if (i == -1) if (i == -1)
throw new IllegalStateException(); throw new IllegalStateException();
lastRet = -1; lastRet = -1;
E x = lastItem;
int ti = takeIndex; lastItem = null;
removeAt(i); // only remove if item still at index
// back up cursor (reset to front if was first element) if (x != null && x == items[i]) {
nextIndex = (i == ti) ? takeIndex : i; boolean removingHead = (i == takeIndex);
checkNext(); removeAt(i);
if (!removingHead)
nextIndex = dec(nextIndex);
}
} finally { } finally {
lock.unlock(); lock.unlock();
} }
} }
} }
} }

View File

@ -869,6 +869,8 @@ public class ConcurrentLinkedDeque<E>
/** /**
* Inserts the specified element at the front of this deque. * Inserts the specified element at the front of this deque.
* As the deque is unbounded, this method will never throw
* {@link IllegalStateException}.
* *
* @throws NullPointerException if the specified element is null * @throws NullPointerException if the specified element is null
*/ */
@ -878,6 +880,8 @@ public class ConcurrentLinkedDeque<E>
/** /**
* Inserts the specified element at the end of this deque. * Inserts the specified element at the end of this deque.
* As the deque is unbounded, this method will never throw
* {@link IllegalStateException}.
* *
* <p>This method is equivalent to {@link #add}. * <p>This method is equivalent to {@link #add}.
* *
@ -889,8 +893,9 @@ public class ConcurrentLinkedDeque<E>
/** /**
* Inserts the specified element at the front of this deque. * Inserts the specified element at the front of this deque.
* As the deque is unbounded, this method will never return {@code false}.
* *
* @return {@code true} always * @return {@code true} (as specified by {@link Deque#offerFirst})
* @throws NullPointerException if the specified element is null * @throws NullPointerException if the specified element is null
*/ */
public boolean offerFirst(E e) { public boolean offerFirst(E e) {
@ -900,10 +905,11 @@ public class ConcurrentLinkedDeque<E>
/** /**
* Inserts the specified element at the end of this deque. * Inserts the specified element at the end of this deque.
* As the deque is unbounded, this method will never return {@code false}.
* *
* <p>This method is equivalent to {@link #add}. * <p>This method is equivalent to {@link #add}.
* *
* @return {@code true} always * @return {@code true} (as specified by {@link Deque#offerLast})
* @throws NullPointerException if the specified element is null * @throws NullPointerException if the specified element is null
*/ */
public boolean offerLast(E e) { public boolean offerLast(E e) {
@ -983,6 +989,7 @@ public class ConcurrentLinkedDeque<E>
/** /**
* Inserts the specified element at the tail of this deque. * Inserts the specified element at the tail of this deque.
* As the deque is unbounded, this method will never return {@code false}.
* *
* @return {@code true} (as specified by {@link Queue#offer}) * @return {@code true} (as specified by {@link Queue#offer})
* @throws NullPointerException if the specified element is null * @throws NullPointerException if the specified element is null
@ -993,6 +1000,8 @@ public class ConcurrentLinkedDeque<E>
/** /**
* Inserts the specified element at the tail of this deque. * Inserts the specified element at the tail of this deque.
* As the deque is unbounded, this method will never throw
* {@link IllegalStateException} or return {@code false}.
* *
* @return {@code true} (as specified by {@link Collection#add}) * @return {@code true} (as specified by {@link Collection#add})
* @throws NullPointerException if the specified element is null * @throws NullPointerException if the specified element is null

View File

@ -269,6 +269,8 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
/** /**
* Inserts the specified element at the tail of this queue. * Inserts the specified element at the tail of this queue.
* As the queue is unbounded, this method will never throw
* {@link IllegalStateException} or return {@code false}.
* *
* @return {@code true} (as specified by {@link Collection#add}) * @return {@code true} (as specified by {@link Collection#add})
* @throws NullPointerException if the specified element is null * @throws NullPointerException if the specified element is null
@ -298,6 +300,7 @@ public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
/** /**
* Inserts the specified element at the tail of this queue. * Inserts the specified element at the tail of this queue.
* As the queue is unbounded, this method will never return {@code false}.
* *
* @return {@code true} (as specified by {@link Queue#offer}) * @return {@code true} (as specified by {@link Queue#offer})
* @throws NullPointerException if the specified element is null * @throws NullPointerException if the specified element is null

View File

@ -374,17 +374,11 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
null, null, 1); null, null, 1);
} }
/** Updater for casHead */
private static final
AtomicReferenceFieldUpdater<ConcurrentSkipListMap, HeadIndex>
headUpdater = AtomicReferenceFieldUpdater.newUpdater
(ConcurrentSkipListMap.class, HeadIndex.class, "head");
/** /**
* compareAndSet head node * compareAndSet head node
*/ */
private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) { private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
return headUpdater.compareAndSet(this, cmp, val); return UNSAFE.compareAndSwapObject(this, headOffset, cmp, val);
} }
/* ---------------- Nodes -------------- */ /* ---------------- Nodes -------------- */
@ -423,28 +417,18 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
this.next = next; this.next = next;
} }
/** Updater for casNext */
static final AtomicReferenceFieldUpdater<Node, Node>
nextUpdater = AtomicReferenceFieldUpdater.newUpdater
(Node.class, Node.class, "next");
/** Updater for casValue */
static final AtomicReferenceFieldUpdater<Node, Object>
valueUpdater = AtomicReferenceFieldUpdater.newUpdater
(Node.class, Object.class, "value");
/** /**
* compareAndSet value field * compareAndSet value field
*/ */
boolean casValue(Object cmp, Object val) { boolean casValue(Object cmp, Object val) {
return valueUpdater.compareAndSet(this, cmp, val); return UNSAFE.compareAndSwapObject(this, valueOffset, cmp, val);
} }
/** /**
* compareAndSet next field * compareAndSet next field
*/ */
boolean casNext(Node<K,V> cmp, Node<K,V> val) { boolean casNext(Node<K,V> cmp, Node<K,V> val) {
return nextUpdater.compareAndSet(this, cmp, val); return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
} }
/** /**
@ -522,6 +506,14 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
return null; return null;
return new AbstractMap.SimpleImmutableEntry<K,V>(key, v); return new AbstractMap.SimpleImmutableEntry<K,V>(key, v);
} }
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long valueOffset =
objectFieldOffset(UNSAFE, "value", Node.class);
private static final long nextOffset =
objectFieldOffset(UNSAFE, "next", Node.class);
} }
/* ---------------- Indexing -------------- */ /* ---------------- Indexing -------------- */
@ -547,16 +539,11 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
this.right = right; this.right = right;
} }
/** Updater for casRight */
static final AtomicReferenceFieldUpdater<Index, Index>
rightUpdater = AtomicReferenceFieldUpdater.newUpdater
(Index.class, Index.class, "right");
/** /**
* compareAndSet right field * compareAndSet right field
*/ */
final boolean casRight(Index<K,V> cmp, Index<K,V> val) { final boolean casRight(Index<K,V> cmp, Index<K,V> val) {
return rightUpdater.compareAndSet(this, cmp, val); return UNSAFE.compareAndSwapObject(this, rightOffset, cmp, val);
} }
/** /**
@ -591,6 +578,12 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
final boolean unlink(Index<K,V> succ) { final boolean unlink(Index<K,V> succ) {
return !indexesDeletedNode() && casRight(succ, succ.right); return !indexesDeletedNode() && casRight(succ, succ.right);
} }
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long rightOffset =
objectFieldOffset(UNSAFE, "right", Index.class);
} }
/* ---------------- Head nodes -------------- */ /* ---------------- Head nodes -------------- */
@ -640,7 +633,8 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
* cast key as Comparable, which may cause ClassCastException, * cast key as Comparable, which may cause ClassCastException,
* which is propagated back to caller. * which is propagated back to caller.
*/ */
private Comparable<? super K> comparable(Object key) throws ClassCastException { private Comparable<? super K> comparable(Object key)
throws ClassCastException {
if (key == null) if (key == null)
throw new NullPointerException(); throw new NullPointerException();
if (comparator != null) if (comparator != null)
@ -799,68 +793,12 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
} }
/** /**
* Specialized variant of findNode to perform Map.get. Does a weak * Gets value for key using findNode.
* traversal, not bothering to fix any deleted index nodes,
* returning early if it happens to see key in index, and passing
* over any deleted base nodes, falling back to getUsingFindNode
* only if it would otherwise return value from an ongoing
* deletion. Also uses "bound" to eliminate need for some
* comparisons (see Pugh Cookbook). Also folds uses of null checks
* and node-skipping because markers have null keys.
* @param okey the key * @param okey the key
* @return the value, or null if absent * @return the value, or null if absent
*/ */
private V doGet(Object okey) { private V doGet(Object okey) {
Comparable<? super K> key = comparable(okey); Comparable<? super K> key = comparable(okey);
Node<K,V> bound = null;
Index<K,V> q = head;
Index<K,V> r = q.right;
Node<K,V> n;
K k;
int c;
for (;;) {
Index<K,V> d;
// Traverse rights
if (r != null && (n = r.node) != bound && (k = n.key) != null) {
if ((c = key.compareTo(k)) > 0) {
q = r;
r = r.right;
continue;
} else if (c == 0) {
Object v = n.value;
return (v != null)? (V)v : getUsingFindNode(key);
} else
bound = n;
}
// Traverse down
if ((d = q.down) != null) {
q = d;
r = d.right;
} else
break;
}
// Traverse nexts
for (n = q.node.next; n != null; n = n.next) {
if ((k = n.key) != null) {
if ((c = key.compareTo(k)) == 0) {
Object v = n.value;
return (v != null)? (V)v : getUsingFindNode(key);
} else if (c < 0)
break;
}
}
return null;
}
/**
* Performs map.get via findNode. Used as a backup if doGet
* encounters an in-progress deletion.
* @param key the key
* @return the value, or null if absent
*/
private V getUsingFindNode(Comparable<? super K> key) {
/* /*
* Loop needed here and elsewhere in case value field goes * Loop needed here and elsewhere in case value field goes
* null just as it is about to be returned, in which case we * null just as it is about to be returned, in which case we
@ -943,7 +881,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
x ^= x << 13; x ^= x << 13;
x ^= x >>> 17; x ^= x >>> 17;
randomSeed = x ^= x << 5; randomSeed = x ^= x << 5;
if ((x & 0x8001) != 0) // test highest and lowest bits if ((x & 0x80000001) != 0) // test highest and lowest bits
return 0; return 0;
int level = 1; int level = 1;
while (((x >>>= 1) & 1) != 0) ++level; while (((x >>>= 1) & 1) != 0) ++level;
@ -1256,7 +1194,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
Node<K,V> n = b.next; Node<K,V> n = b.next;
for (;;) { for (;;) {
if (n == null) if (n == null)
return (b.isBaseHeader())? null : b; return b.isBaseHeader() ? null : b;
Node<K,V> f = n.next; // inconsistent read Node<K,V> f = n.next; // inconsistent read
if (n != b.next) if (n != b.next)
break; break;
@ -1374,7 +1312,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
Node<K,V> n = b.next; Node<K,V> n = b.next;
for (;;) { for (;;) {
if (n == null) if (n == null)
return ((rel & LT) == 0 || b.isBaseHeader())? null : b; return ((rel & LT) == 0 || b.isBaseHeader()) ? null : b;
Node<K,V> f = n.next; Node<K,V> f = n.next;
if (n != b.next) // inconsistent read if (n != b.next) // inconsistent read
break; break;
@ -1390,7 +1328,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
(c < 0 && (rel & LT) == 0)) (c < 0 && (rel & LT) == 0))
return n; return n;
if ( c <= 0 && (rel & LT) != 0) if ( c <= 0 && (rel & LT) != 0)
return (b.isBaseHeader())? null : b; return b.isBaseHeader() ? null : b;
b = n; b = n;
n = f; n = f;
} }
@ -1744,7 +1682,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
if (n.getValidValue() != null) if (n.getValidValue() != null)
++count; ++count;
} }
return (count >= Integer.MAX_VALUE)? Integer.MAX_VALUE : (int)count; return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) count;
} }
/** /**
@ -2099,7 +2037,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
*/ */
public K lowerKey(K key) { public K lowerKey(K key) {
Node<K,V> n = findNear(key, LT); Node<K,V> n = findNear(key, LT);
return (n == null)? null : n.key; return (n == null) ? null : n.key;
} }
/** /**
@ -2123,7 +2061,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
*/ */
public K floorKey(K key) { public K floorKey(K key) {
Node<K,V> n = findNear(key, LT|EQ); Node<K,V> n = findNear(key, LT|EQ);
return (n == null)? null : n.key; return (n == null) ? null : n.key;
} }
/** /**
@ -2145,7 +2083,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
*/ */
public K ceilingKey(K key) { public K ceilingKey(K key) {
Node<K,V> n = findNear(key, GT|EQ); Node<K,V> n = findNear(key, GT|EQ);
return (n == null)? null : n.key; return (n == null) ? null : n.key;
} }
/** /**
@ -2169,7 +2107,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
*/ */
public K higherKey(K key) { public K higherKey(K key) {
Node<K,V> n = findNear(key, GT); Node<K,V> n = findNear(key, GT);
return (n == null)? null : n.key; return (n == null) ? null : n.key;
} }
/** /**
@ -2342,7 +2280,8 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
return list; return list;
} }
static final class KeySet<E> extends AbstractSet<E> implements NavigableSet<E> { static final class KeySet<E>
extends AbstractSet<E> implements NavigableSet<E> {
private final ConcurrentNavigableMap<E,Object> m; private final ConcurrentNavigableMap<E,Object> m;
KeySet(ConcurrentNavigableMap<E,Object> map) { m = map; } KeySet(ConcurrentNavigableMap<E,Object> map) { m = map; }
public int size() { return m.size(); } public int size() { return m.size(); }
@ -2359,11 +2298,11 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
public E last() { return m.lastKey(); } public E last() { return m.lastKey(); }
public E pollFirst() { public E pollFirst() {
Map.Entry<E,Object> e = m.pollFirstEntry(); Map.Entry<E,Object> e = m.pollFirstEntry();
return e == null? null : e.getKey(); return (e == null) ? null : e.getKey();
} }
public E pollLast() { public E pollLast() {
Map.Entry<E,Object> e = m.pollLastEntry(); Map.Entry<E,Object> e = m.pollLastEntry();
return e == null? null : e.getKey(); return (e == null) ? null : e.getKey();
} }
public Iterator<E> iterator() { public Iterator<E> iterator() {
if (m instanceof ConcurrentSkipListMap) if (m instanceof ConcurrentSkipListMap)
@ -2710,9 +2649,9 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
rel &= ~m.LT; rel &= ~m.LT;
} }
if (tooLow(key)) if (tooLow(key))
return ((rel & m.LT) != 0)? null : lowestEntry(); return ((rel & m.LT) != 0) ? null : lowestEntry();
if (tooHigh(key)) if (tooHigh(key))
return ((rel & m.LT) != 0)? highestEntry() : null; return ((rel & m.LT) != 0) ? highestEntry() : null;
for (;;) { for (;;) {
Node<K,V> n = m.findNear(key, rel); Node<K,V> n = m.findNear(key, rel);
if (n == null || !inBounds(n.key)) if (n == null || !inBounds(n.key))
@ -2783,7 +2722,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
public V remove(Object key) { public V remove(Object key) {
K k = (K)key; K k = (K)key;
return (!inBounds(k))? null : m.remove(k); return (!inBounds(k)) ? null : m.remove(k);
} }
public int size() { public int size() {
@ -2794,7 +2733,7 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
if (n.getValidValue() != null) if (n.getValidValue() != null)
++count; ++count;
} }
return count >= Integer.MAX_VALUE? Integer.MAX_VALUE : (int)count; return count >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)count;
} }
public boolean isEmpty() { public boolean isEmpty() {
@ -2972,27 +2911,27 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
} }
public K firstKey() { public K firstKey() {
return isDescending? highestKey() : lowestKey(); return isDescending ? highestKey() : lowestKey();
} }
public K lastKey() { public K lastKey() {
return isDescending? lowestKey() : highestKey(); return isDescending ? lowestKey() : highestKey();
} }
public Map.Entry<K,V> firstEntry() { public Map.Entry<K,V> firstEntry() {
return isDescending? highestEntry() : lowestEntry(); return isDescending ? highestEntry() : lowestEntry();
} }
public Map.Entry<K,V> lastEntry() { public Map.Entry<K,V> lastEntry() {
return isDescending? lowestEntry() : highestEntry(); return isDescending ? lowestEntry() : highestEntry();
} }
public Map.Entry<K,V> pollFirstEntry() { public Map.Entry<K,V> pollFirstEntry() {
return isDescending? removeHighest() : removeLowest(); return isDescending ? removeHighest() : removeLowest();
} }
public Map.Entry<K,V> pollLastEntry() { public Map.Entry<K,V> pollLastEntry() {
return isDescending? removeLowest() : removeHighest(); return isDescending ? removeLowest() : removeHighest();
} }
/* ---------------- Submap Views -------------- */ /* ---------------- Submap Views -------------- */
@ -3141,4 +3080,22 @@ public class ConcurrentSkipListMap<K,V> extends AbstractMap<K,V>
} }
} }
} }
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long headOffset =
objectFieldOffset(UNSAFE, "head", ConcurrentSkipListMap.class);
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
String field, Class<?> klazz) {
try {
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
} catch (NoSuchFieldException e) {
// Convert Exception to corresponding Error
NoSuchFieldError error = new NoSuchFieldError(field);
error.initCause(e);
throw error;
}
}
} }

View File

@ -832,7 +832,7 @@ public class CopyOnWriteArrayList<E>
} }
/** /**
* Save the state of the list to a stream (i.e., serialize it). * Saves the state of the list to a stream (that is, serializes it).
* *
* @serialData The length of the array backing the list is emitted * @serialData The length of the array backing the list is emitted
* (int), followed by all of its elements (each an Object) * (int), followed by all of its elements (each an Object)
@ -842,27 +842,25 @@ public class CopyOnWriteArrayList<E>
private void writeObject(java.io.ObjectOutputStream s) private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{ throws java.io.IOException{
// Write out element count, and any hidden stuff
s.defaultWriteObject(); s.defaultWriteObject();
Object[] elements = getArray(); Object[] elements = getArray();
int len = elements.length;
// Write out array length // Write out array length
s.writeInt(len); s.writeInt(elements.length);
// Write out all elements in the proper order. // Write out all elements in the proper order.
for (int i = 0; i < len; i++) for (Object element : elements)
s.writeObject(elements[i]); s.writeObject(element);
} }
/** /**
* Reconstitute the list from a stream (i.e., deserialize it). * Reconstitutes the list from a stream (that is, deserializes it).
*
* @param s the stream * @param s the stream
*/ */
private void readObject(java.io.ObjectInputStream s) private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException { throws java.io.IOException, ClassNotFoundException {
// Read in size, and any hidden stuff
s.defaultReadObject(); s.defaultReadObject();
// bind to new lock // bind to new lock

View File

@ -525,8 +525,8 @@ public class ForkJoinPool extends AbstractExecutorService {
*/ */
private volatile long eventWaiters; private volatile long eventWaiters;
private static final int EVENT_COUNT_SHIFT = 32; private static final int EVENT_COUNT_SHIFT = 32;
private static final long WAITER_ID_MASK = (1L << 16) - 1L; private static final int WAITER_ID_MASK = (1 << 16) - 1;
/** /**
* A counter for events that may wake up worker threads: * A counter for events that may wake up worker threads:
@ -615,7 +615,7 @@ public class ForkJoinPool extends AbstractExecutorService {
// are usually manually inlined by callers // are usually manually inlined by callers
/** /**
* Increments running count part of workerCounts * Increments running count part of workerCounts.
*/ */
final void incrementRunningCount() { final void incrementRunningCount() {
int c; int c;
@ -625,7 +625,17 @@ public class ForkJoinPool extends AbstractExecutorService {
} }
/** /**
* Tries to decrement running count unless already zero * Tries to increment running count part of workerCounts.
*/
final boolean tryIncrementRunningCount() {
int c;
return UNSAFE.compareAndSwapInt(this, workerCountsOffset,
c = workerCounts,
c + ONE_RUNNING);
}
/**
* Tries to decrement running count unless already zero.
*/ */
final boolean tryDecrementRunningCount() { final boolean tryDecrementRunningCount() {
int wc = workerCounts; int wc = workerCounts;
@ -698,10 +708,11 @@ public class ForkJoinPool extends AbstractExecutorService {
for (k = 0; k < n && ws[k] != null; ++k) for (k = 0; k < n && ws[k] != null; ++k)
; ;
if (k == n) if (k == n)
ws = Arrays.copyOf(ws, n << 1); ws = workers = Arrays.copyOf(ws, n << 1);
} }
ws[k] = w; ws[k] = w;
workers = ws; // volatile array write ensures slot visibility int c = eventCount; // advance event count to ensure visibility
UNSAFE.compareAndSwapInt(this, eventCountOffset, c, c+1);
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@ -734,7 +745,7 @@ public class ForkJoinPool extends AbstractExecutorService {
*/ */
final void workerTerminated(ForkJoinWorkerThread w) { final void workerTerminated(ForkJoinWorkerThread w) {
forgetWorker(w); forgetWorker(w);
decrementWorkerCounts(w.isTrimmed()? 0 : ONE_RUNNING, ONE_TOTAL); decrementWorkerCounts(w.isTrimmed() ? 0 : ONE_RUNNING, ONE_TOTAL);
while (w.stealCount != 0) // collect final count while (w.stealCount != 0) // collect final count
tryAccumulateStealCount(w); tryAccumulateStealCount(w);
tryTerminate(false); tryTerminate(false);
@ -746,24 +757,23 @@ public class ForkJoinPool extends AbstractExecutorService {
* Releases workers blocked on a count not equal to current count. * Releases workers blocked on a count not equal to current count.
* Normally called after precheck that eventWaiters isn't zero to * Normally called after precheck that eventWaiters isn't zero to
* avoid wasted array checks. Gives up upon a change in count or * avoid wasted array checks. Gives up upon a change in count or
* upon releasing two workers, letting others take over. * upon releasing four workers, letting others take over.
*/ */
private void releaseEventWaiters() { private void releaseEventWaiters() {
ForkJoinWorkerThread[] ws = workers; ForkJoinWorkerThread[] ws = workers;
int n = ws.length; int n = ws.length;
long h = eventWaiters; long h = eventWaiters;
int ec = eventCount; int ec = eventCount;
boolean releasedOne = false; int releases = 4;
ForkJoinWorkerThread w; int id; ForkJoinWorkerThread w; int id;
while ((id = ((int)(h & WAITER_ID_MASK)) - 1) >= 0 && while ((id = (((int)h) & WAITER_ID_MASK) - 1) >= 0 &&
(int)(h >>> EVENT_COUNT_SHIFT) != ec && (int)(h >>> EVENT_COUNT_SHIFT) != ec &&
id < n && (w = ws[id]) != null) { id < n && (w = ws[id]) != null) {
if (UNSAFE.compareAndSwapLong(this, eventWaitersOffset, if (UNSAFE.compareAndSwapLong(this, eventWaitersOffset,
h, w.nextWaiter)) { h, w.nextWaiter)) {
LockSupport.unpark(w); LockSupport.unpark(w);
if (releasedOne) // exit on second release if (--releases == 0)
break; break;
releasedOne = true;
} }
if (eventCount != ec) if (eventCount != ec)
break; break;
@ -793,7 +803,7 @@ public class ForkJoinPool extends AbstractExecutorService {
long nh = (((long)ec) << EVENT_COUNT_SHIFT) | ((long)(w.poolIndex+1)); long nh = (((long)ec) << EVENT_COUNT_SHIFT) | ((long)(w.poolIndex+1));
long h; long h;
while ((runState < SHUTDOWN || !tryTerminate(false)) && while ((runState < SHUTDOWN || !tryTerminate(false)) &&
(((int)((h = eventWaiters) & WAITER_ID_MASK)) == 0 || (((int)(h = eventWaiters) & WAITER_ID_MASK) == 0 ||
(int)(h >>> EVENT_COUNT_SHIFT) == ec) && (int)(h >>> EVENT_COUNT_SHIFT) == ec) &&
eventCount == ec) { eventCount == ec) {
if (UNSAFE.compareAndSwapLong(this, eventWaitersOffset, if (UNSAFE.compareAndSwapLong(this, eventWaitersOffset,
@ -820,9 +830,9 @@ public class ForkJoinPool extends AbstractExecutorService {
if (tryAccumulateStealCount(w)) { // transfer while idle if (tryAccumulateStealCount(w)) { // transfer while idle
boolean untimed = (w.nextWaiter != 0L || boolean untimed = (w.nextWaiter != 0L ||
(workerCounts & RUNNING_COUNT_MASK) <= 1); (workerCounts & RUNNING_COUNT_MASK) <= 1);
long startTime = untimed? 0 : System.nanoTime(); long startTime = untimed ? 0 : System.nanoTime();
Thread.interrupted(); // clear/ignore interrupt Thread.interrupted(); // clear/ignore interrupt
if (eventCount != ec || w.isTerminating()) if (w.isTerminating() || eventCount != ec)
break; // recheck after clear break; // recheck after clear
if (untimed) if (untimed)
LockSupport.park(w); LockSupport.park(w);
@ -860,7 +870,8 @@ public class ForkJoinPool extends AbstractExecutorService {
if ((sw = spareWaiters) != 0 && if ((sw = spareWaiters) != 0 &&
(id = (sw & SPARE_ID_MASK) - 1) >= 0 && (id = (sw & SPARE_ID_MASK) - 1) >= 0 &&
id < n && (w = ws[id]) != null && id < n && (w = ws[id]) != null &&
(workerCounts & RUNNING_COUNT_MASK) < parallelism && (runState >= TERMINATING ||
(workerCounts & RUNNING_COUNT_MASK) < parallelism) &&
spareWaiters == sw && spareWaiters == sw &&
UNSAFE.compareAndSwapInt(this, spareWaitersOffset, UNSAFE.compareAndSwapInt(this, spareWaitersOffset,
sw, w.nextSpare)) { sw, w.nextSpare)) {
@ -914,12 +925,8 @@ public class ForkJoinPool extends AbstractExecutorService {
break; break;
} }
w.start(recordWorker(w), ueh); w.start(recordWorker(w), ueh);
if ((workerCounts >>> TOTAL_COUNT_SHIFT) >= pc) { if ((workerCounts >>> TOTAL_COUNT_SHIFT) >= pc)
int c; // advance event count
UNSAFE.compareAndSwapInt(this, eventCountOffset,
c = eventCount, c+1);
break; // add at most one unless total below target break; // add at most one unless total below target
}
} }
} }
if (eventWaiters != 0L) if (eventWaiters != 0L)
@ -955,7 +962,7 @@ public class ForkJoinPool extends AbstractExecutorService {
} }
else if ((h = eventWaiters) != 0L) { else if ((h = eventWaiters) != 0L) {
long nh; long nh;
int id = ((int)(h & WAITER_ID_MASK)) - 1; int id = (((int)h) & WAITER_ID_MASK) - 1;
if (id >= 0 && id < n && (w = ws[id]) != null && if (id >= 0 && id < n && (w = ws[id]) != null &&
(nh = w.nextWaiter) != 0L && // keep at least one worker (nh = w.nextWaiter) != 0L && // keep at least one worker
UNSAFE.compareAndSwapLong(this, eventWaitersOffset, h, nh)) UNSAFE.compareAndSwapLong(this, eventWaitersOffset, h, nh))
@ -1003,24 +1010,31 @@ public class ForkJoinPool extends AbstractExecutorService {
int pc = parallelism; int pc = parallelism;
while (w.runState == 0) { while (w.runState == 0) {
int rs = runState; int rs = runState;
if (rs >= TERMINATING) { // propagate shutdown if (rs >= TERMINATING) { // propagate shutdown
w.shutdown(); w.shutdown();
break; break;
} }
if ((inactivate || (active && (rs & ACTIVE_COUNT_MASK) >= pc)) && if ((inactivate || (active && (rs & ACTIVE_COUNT_MASK) >= pc)) &&
UNSAFE.compareAndSwapInt(this, runStateOffset, rs, rs - 1)) UNSAFE.compareAndSwapInt(this, runStateOffset, rs, --rs)) {
inactivate = active = w.active = false; inactivate = active = w.active = false;
int wc = workerCounts; if (rs == SHUTDOWN) { // all inactive and shut down
tryTerminate(false);
continue;
}
}
int wc = workerCounts; // try to suspend as spare
if ((wc & RUNNING_COUNT_MASK) > pc) { if ((wc & RUNNING_COUNT_MASK) > pc) {
if (!(inactivate |= active) && // must inactivate to suspend if (!(inactivate |= active) && // must inactivate to suspend
workerCounts == wc && // try to suspend as spare workerCounts == wc &&
UNSAFE.compareAndSwapInt(this, workerCountsOffset, UNSAFE.compareAndSwapInt(this, workerCountsOffset,
wc, wc - ONE_RUNNING)) wc, wc - ONE_RUNNING))
w.suspendAsSpare(); w.suspendAsSpare();
} }
else if ((wc >>> TOTAL_COUNT_SHIFT) < pc) else if ((wc >>> TOTAL_COUNT_SHIFT) < pc)
helpMaintainParallelism(); // not enough workers helpMaintainParallelism(); // not enough workers
else if (!ran) { else if (ran)
break;
else {
long h = eventWaiters; long h = eventWaiters;
int ec = eventCount; int ec = eventCount;
if (h != 0L && (int)(h >>> EVENT_COUNT_SHIFT) != ec) if (h != 0L && (int)(h >>> EVENT_COUNT_SHIFT) != ec)
@ -1032,8 +1046,6 @@ public class ForkJoinPool extends AbstractExecutorService {
else if (!(inactivate |= active)) else if (!(inactivate |= active))
eventSync(w, wec); // must inactivate before sync eventSync(w, wec); // must inactivate before sync
} }
else
break;
} }
} }
@ -1043,35 +1055,67 @@ public class ForkJoinPool extends AbstractExecutorService {
* *
* @param joinMe the task to join * @param joinMe the task to join
* @param worker the current worker thread * @param worker the current worker thread
* @param timed true if wait should time out
* @param nanos timeout value if timed
*/ */
final void awaitJoin(ForkJoinTask<?> joinMe, ForkJoinWorkerThread worker) { final void awaitJoin(ForkJoinTask<?> joinMe, ForkJoinWorkerThread worker,
boolean timed, long nanos) {
long startTime = timed ? System.nanoTime() : 0L;
int retries = 2 + (parallelism >> 2); // #helpJoins before blocking int retries = 2 + (parallelism >> 2); // #helpJoins before blocking
boolean running = true; // false when count decremented
while (joinMe.status >= 0) { while (joinMe.status >= 0) {
int wc; if (runState >= TERMINATING) {
worker.helpJoinTask(joinMe); joinMe.cancelIgnoringExceptions();
break;
}
running = worker.helpJoinTask(joinMe, running);
if (joinMe.status < 0) if (joinMe.status < 0)
break; break;
else if (retries > 0) if (retries > 0) {
--retries; --retries;
else if (((wc = workerCounts) & RUNNING_COUNT_MASK) != 0 && continue;
UNSAFE.compareAndSwapInt(this, workerCountsOffset,
wc, wc - ONE_RUNNING)) {
int stat, c; long h;
while ((stat = joinMe.status) >= 0 &&
(h = eventWaiters) != 0L && // help release others
(int)(h >>> EVENT_COUNT_SHIFT) != eventCount)
releaseEventWaiters();
if (stat >= 0 &&
((workerCounts & RUNNING_COUNT_MASK) == 0 ||
(stat =
joinMe.internalAwaitDone(JOIN_TIMEOUT_MILLIS)) >= 0))
helpMaintainParallelism(); // timeout or no running workers
do {} while (!UNSAFE.compareAndSwapInt
(this, workerCountsOffset,
c = workerCounts, c + ONE_RUNNING));
if (stat < 0)
break; // else restart
} }
int wc = workerCounts;
if ((wc & RUNNING_COUNT_MASK) != 0) {
if (running) {
if (!UNSAFE.compareAndSwapInt(this, workerCountsOffset,
wc, wc - ONE_RUNNING))
continue;
running = false;
}
long h = eventWaiters;
if (h != 0L && (int)(h >>> EVENT_COUNT_SHIFT) != eventCount)
releaseEventWaiters();
if ((workerCounts & RUNNING_COUNT_MASK) != 0) {
long ms; int ns;
if (!timed) {
ms = JOIN_TIMEOUT_MILLIS;
ns = 0;
}
else { // at most JOIN_TIMEOUT_MILLIS per wait
long nt = nanos - (System.nanoTime() - startTime);
if (nt <= 0L)
break;
ms = nt / 1000000;
if (ms > JOIN_TIMEOUT_MILLIS) {
ms = JOIN_TIMEOUT_MILLIS;
ns = 0;
}
else
ns = (int) (nt % 1000000);
}
joinMe.internalAwaitDone(ms, ns);
}
if (joinMe.status < 0)
break;
}
helpMaintainParallelism();
}
if (!running) {
int c;
do {} while (!UNSAFE.compareAndSwapInt
(this, workerCountsOffset,
c = workerCounts, c + ONE_RUNNING));
} }
} }
@ -1082,9 +1126,10 @@ public class ForkJoinPool extends AbstractExecutorService {
throws InterruptedException { throws InterruptedException {
while (!blocker.isReleasable()) { while (!blocker.isReleasable()) {
int wc = workerCounts; int wc = workerCounts;
if ((wc & RUNNING_COUNT_MASK) != 0 && if ((wc & RUNNING_COUNT_MASK) == 0)
UNSAFE.compareAndSwapInt(this, workerCountsOffset, helpMaintainParallelism();
wc, wc - ONE_RUNNING)) { else if (UNSAFE.compareAndSwapInt(this, workerCountsOffset,
wc, wc - ONE_RUNNING)) {
try { try {
while (!blocker.isReleasable()) { while (!blocker.isReleasable()) {
long h = eventWaiters; long h = eventWaiters;
@ -1129,12 +1174,11 @@ public class ForkJoinPool extends AbstractExecutorService {
// Finish now if all threads terminated; else in some subsequent call // Finish now if all threads terminated; else in some subsequent call
if ((workerCounts >>> TOTAL_COUNT_SHIFT) == 0) { if ((workerCounts >>> TOTAL_COUNT_SHIFT) == 0) {
advanceRunLevel(TERMINATED); advanceRunLevel(TERMINATED);
termination.arrive(); termination.forceTermination();
} }
return true; return true;
} }
/** /**
* Actions on transition to TERMINATING * Actions on transition to TERMINATING
* *
@ -1325,17 +1369,13 @@ public class ForkJoinPool extends AbstractExecutorService {
// Execution methods // Execution methods
/** /**
* Common code for execute, invoke and submit * Submits task and creates, starts, or resumes some workers if necessary
*/ */
private <T> void doSubmit(ForkJoinTask<T> task) { private <T> void doSubmit(ForkJoinTask<T> task) {
if (task == null)
throw new NullPointerException();
if (runState >= SHUTDOWN)
throw new RejectedExecutionException();
submissionQueue.offer(task); submissionQueue.offer(task);
int c; // try to increment event count -- CAS failure OK int c; // try to increment event count -- CAS failure OK
UNSAFE.compareAndSwapInt(this, eventCountOffset, c = eventCount, c+1); UNSAFE.compareAndSwapInt(this, eventCountOffset, c = eventCount, c+1);
helpMaintainParallelism(); // create, start, or resume some workers helpMaintainParallelism();
} }
/** /**
@ -1348,8 +1388,33 @@ public class ForkJoinPool extends AbstractExecutorService {
* scheduled for execution * scheduled for execution
*/ */
public <T> T invoke(ForkJoinTask<T> task) { public <T> T invoke(ForkJoinTask<T> task) {
doSubmit(task); if (task == null)
return task.join(); throw new NullPointerException();
if (runState >= SHUTDOWN)
throw new RejectedExecutionException();
Thread t = Thread.currentThread();
if ((t instanceof ForkJoinWorkerThread) &&
((ForkJoinWorkerThread)t).pool == this)
return task.invoke(); // bypass submit if in same pool
else {
doSubmit(task);
return task.join();
}
}
/**
* Unless terminating, forks task if within an ongoing FJ
* computation in the current pool, else submits as external task.
*/
private <T> void forkOrSubmit(ForkJoinTask<T> task) {
if (runState >= SHUTDOWN)
throw new RejectedExecutionException();
Thread t = Thread.currentThread();
if ((t instanceof ForkJoinWorkerThread) &&
((ForkJoinWorkerThread)t).pool == this)
task.fork();
else
doSubmit(task);
} }
/** /**
@ -1361,7 +1426,9 @@ public class ForkJoinPool extends AbstractExecutorService {
* scheduled for execution * scheduled for execution
*/ */
public void execute(ForkJoinTask<?> task) { public void execute(ForkJoinTask<?> task) {
doSubmit(task); if (task == null)
throw new NullPointerException();
forkOrSubmit(task);
} }
// AbstractExecutorService methods // AbstractExecutorService methods
@ -1372,12 +1439,14 @@ public class ForkJoinPool extends AbstractExecutorService {
* scheduled for execution * scheduled for execution
*/ */
public void execute(Runnable task) { public void execute(Runnable task) {
if (task == null)
throw new NullPointerException();
ForkJoinTask<?> job; ForkJoinTask<?> job;
if (task instanceof ForkJoinTask<?>) // avoid re-wrap if (task instanceof ForkJoinTask<?>) // avoid re-wrap
job = (ForkJoinTask<?>) task; job = (ForkJoinTask<?>) task;
else else
job = ForkJoinTask.adapt(task, null); job = ForkJoinTask.adapt(task, null);
doSubmit(job); forkOrSubmit(job);
} }
/** /**
@ -1390,7 +1459,9 @@ public class ForkJoinPool extends AbstractExecutorService {
* scheduled for execution * scheduled for execution
*/ */
public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) { public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task) {
doSubmit(task); if (task == null)
throw new NullPointerException();
forkOrSubmit(task);
return task; return task;
} }
@ -1400,8 +1471,10 @@ public class ForkJoinPool extends AbstractExecutorService {
* scheduled for execution * scheduled for execution
*/ */
public <T> ForkJoinTask<T> submit(Callable<T> task) { public <T> ForkJoinTask<T> submit(Callable<T> task) {
if (task == null)
throw new NullPointerException();
ForkJoinTask<T> job = ForkJoinTask.adapt(task); ForkJoinTask<T> job = ForkJoinTask.adapt(task);
doSubmit(job); forkOrSubmit(job);
return job; return job;
} }
@ -1411,8 +1484,10 @@ public class ForkJoinPool extends AbstractExecutorService {
* scheduled for execution * scheduled for execution
*/ */
public <T> ForkJoinTask<T> submit(Runnable task, T result) { public <T> ForkJoinTask<T> submit(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
ForkJoinTask<T> job = ForkJoinTask.adapt(task, result); ForkJoinTask<T> job = ForkJoinTask.adapt(task, result);
doSubmit(job); forkOrSubmit(job);
return job; return job;
} }
@ -1422,12 +1497,14 @@ public class ForkJoinPool extends AbstractExecutorService {
* scheduled for execution * scheduled for execution
*/ */
public ForkJoinTask<?> submit(Runnable task) { public ForkJoinTask<?> submit(Runnable task) {
if (task == null)
throw new NullPointerException();
ForkJoinTask<?> job; ForkJoinTask<?> job;
if (task instanceof ForkJoinTask<?>) // avoid re-wrap if (task instanceof ForkJoinTask<?>) // avoid re-wrap
job = (ForkJoinTask<?>) task; job = (ForkJoinTask<?>) task;
else else
job = ForkJoinTask.adapt(task, null); job = ForkJoinTask.adapt(task, null);
doSubmit(job); forkOrSubmit(job);
return job; return job;
} }
@ -1725,8 +1802,11 @@ public class ForkJoinPool extends AbstractExecutorService {
* commenced but not yet completed. This method may be useful for * commenced but not yet completed. This method may be useful for
* debugging. A return of {@code true} reported a sufficient * debugging. A return of {@code true} reported a sufficient
* period after shutdown may indicate that submitted tasks have * period after shutdown may indicate that submitted tasks have
* ignored or suppressed interruption, causing this executor not * ignored or suppressed interruption, or are waiting for IO,
* to properly terminate. * causing this executor not to properly terminate. (See the
* advisory notes for class {@link ForkJoinTask} stating that
* tasks should not normally entail blocking operations. But if
* they do, they must abort them on interrupt.)
* *
* @return {@code true} if terminating but not yet terminated * @return {@code true} if terminating but not yet terminated
*/ */
@ -1764,10 +1844,11 @@ public class ForkJoinPool extends AbstractExecutorService {
public boolean awaitTermination(long timeout, TimeUnit unit) public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException { throws InterruptedException {
try { try {
return termination.awaitAdvanceInterruptibly(0, timeout, unit) > 0; termination.awaitAdvanceInterruptibly(0, timeout, unit);
} catch (TimeoutException ex) { } catch (TimeoutException ex) {
return false; return false;
} }
return true;
} }
/** /**

View File

@ -42,6 +42,16 @@ import java.util.List;
import java.util.RandomAccess; import java.util.RandomAccess;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/** /**
* Abstract base class for tasks that run within a {@link ForkJoinPool}. * Abstract base class for tasks that run within a {@link ForkJoinPool}.
@ -129,6 +139,16 @@ import java.util.WeakHashMap;
* result in exceptions or errors, possibly including * result in exceptions or errors, possibly including
* {@code ClassCastException}. * {@code ClassCastException}.
* *
* <p>Method {@link #join} and its variants are appropriate for use
* only when completion dependencies are acyclic; that is, the
* parallel computation can be described as a directed acyclic graph
* (DAG). Otherwise, executions may encounter a form of deadlock as
* tasks cyclically wait for each other. However, this framework
* supports other methods and techniques (for example the use of
* {@link Phaser}, {@link #helpQuiesce}, and {@link #complete}) that
* may be of use in constructing custom subclasses for problems that
* are not statically structured as DAGs.
*
* <p>Most base support methods are {@code final}, to prevent * <p>Most base support methods are {@code final}, to prevent
* overriding of implementations that are intrinsically tied to the * overriding of implementations that are intrinsically tied to the
* underlying lightweight task scheduling framework. Developers * underlying lightweight task scheduling framework. Developers
@ -143,9 +163,10 @@ import java.util.WeakHashMap;
* computation. Large tasks should be split into smaller subtasks, * computation. Large tasks should be split into smaller subtasks,
* usually via recursive decomposition. As a very rough rule of thumb, * usually via recursive decomposition. As a very rough rule of thumb,
* a task should perform more than 100 and less than 10000 basic * a task should perform more than 100 and less than 10000 basic
* computational steps. If tasks are too big, then parallelism cannot * computational steps, and should avoid indefinite looping. If tasks
* improve throughput. If too small, then memory and internal task * are too big, then parallelism cannot improve throughput. If too
* maintenance overhead may overwhelm processing. * small, then memory and internal task maintenance overhead may
* overwhelm processing.
* *
* <p>This class provides {@code adapt} methods for {@link Runnable} * <p>This class provides {@code adapt} methods for {@link Runnable}
* and {@link Callable}, that may be of use when mixing execution of * and {@link Callable}, that may be of use when mixing execution of
@ -241,66 +262,84 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
setCompletion(EXCEPTIONAL); setCompletion(EXCEPTIONAL);
} }
/**
* Blocks a worker thread until completion. Called only by
* pool. Currently unused -- pool-based waits use timeout
* version below.
*/
final void internalAwaitDone() {
int s; // the odd construction reduces lock bias effects
while ((s = status) >= 0) {
try {
synchronized (this) {
if (UNSAFE.compareAndSwapInt(this, statusOffset, s,SIGNAL))
wait();
}
} catch (InterruptedException ie) {
cancelIfTerminating();
}
}
}
/** /**
* Blocks a worker thread until completed or timed out. Called * Blocks a worker thread until completed or timed out. Called
* only by pool. * only by pool.
*
* @return status on exit
*/ */
final int internalAwaitDone(long millis) { final void internalAwaitDone(long millis, int nanos) {
int s; int s = status;
if ((s = status) >= 0) { if ((s == 0 &&
try { UNSAFE.compareAndSwapInt(this, statusOffset, 0, SIGNAL)) ||
s > 0) {
try { // the odd construction reduces lock bias effects
synchronized (this) { synchronized (this) {
if (UNSAFE.compareAndSwapInt(this, statusOffset, s,SIGNAL)) if (status > 0)
wait(millis, 0); wait(millis, nanos);
else
notifyAll();
} }
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
cancelIfTerminating(); cancelIfTerminating();
} }
s = status;
} }
return s;
} }
/** /**
* Blocks a non-worker-thread until completion. * Blocks a non-worker-thread until completion.
*/ */
private void externalAwaitDone() { private void externalAwaitDone() {
int s; if (status >= 0) {
while ((s = status) >= 0) { boolean interrupted = false;
synchronized (this) { synchronized (this) {
if (UNSAFE.compareAndSwapInt(this, statusOffset, s, SIGNAL)){ for (;;) {
boolean interrupted = false; int s = status;
while (status >= 0) { if (s == 0)
UNSAFE.compareAndSwapInt(this, statusOffset,
0, SIGNAL);
else if (s < 0) {
notifyAll();
break;
}
else {
try { try {
wait(); wait();
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
interrupted = true; interrupted = true;
} }
} }
if (interrupted) }
Thread.currentThread().interrupt(); }
break; if (interrupted)
Thread.currentThread().interrupt();
}
}
/**
* Blocks a non-worker-thread until completion or interruption or timeout.
*/
private void externalInterruptibleAwaitDone(boolean timed, long nanos)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (status >= 0) {
long startTime = timed ? System.nanoTime() : 0L;
synchronized (this) {
for (;;) {
long nt;
int s = status;
if (s == 0)
UNSAFE.compareAndSwapInt(this, statusOffset,
0, SIGNAL);
else if (s < 0) {
notifyAll();
break;
}
else if (!timed)
wait();
else if ((nt = nanos - (System.nanoTime()-startTime)) > 0L)
wait(nt / 1000000, (int)(nt % 1000000));
else
break;
} }
} }
} }
@ -335,7 +374,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* #isDone} returning {@code true}. * #isDone} returning {@code true}.
* *
* <p>This method may be invoked only from within {@code * <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method * ForkJoinPool} computations (as may be determined using method
* {@link #inForkJoinPool}). Attempts to invoke in other contexts * {@link #inForkJoinPool}). Attempts to invoke in other contexts
* result in exceptions or errors, possibly including {@code * result in exceptions or errors, possibly including {@code
* ClassCastException}. * ClassCastException}.
@ -349,10 +388,13 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
} }
/** /**
* Returns the result of the computation when it {@link #isDone is done}. * Returns the result of the computation when it {@link #isDone is
* This method differs from {@link #get()} in that * done}. This method differs from {@link #get()} in that
* abnormal completion results in {@code RuntimeException} or * abnormal completion results in {@code RuntimeException} or
* {@code Error}, not {@code ExecutionException}. * {@code Error}, not {@code ExecutionException}, and that
* interrupts of the calling thread do <em>not</em> cause the
* method to abruptly return by throwing {@code
* InterruptedException}.
* *
* @return the computed result * @return the computed result
*/ */
@ -394,7 +436,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* unprocessed. * unprocessed.
* *
* <p>This method may be invoked only from within {@code * <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method * ForkJoinPool} computations (as may be determined using method
* {@link #inForkJoinPool}). Attempts to invoke in other contexts * {@link #inForkJoinPool}). Attempts to invoke in other contexts
* result in exceptions or errors, possibly including {@code * result in exceptions or errors, possibly including {@code
* ClassCastException}. * ClassCastException}.
@ -422,7 +464,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* normally or exceptionally, or left unprocessed. * normally or exceptionally, or left unprocessed.
* *
* <p>This method may be invoked only from within {@code * <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method * ForkJoinPool} computations (as may be determined using method
* {@link #inForkJoinPool}). Attempts to invoke in other contexts * {@link #inForkJoinPool}). Attempts to invoke in other contexts
* result in exceptions or errors, possibly including {@code * result in exceptions or errors, possibly including {@code
* ClassCastException}. * ClassCastException}.
@ -477,7 +519,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* unprocessed. * unprocessed.
* *
* <p>This method may be invoked only from within {@code * <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method * ForkJoinPool} computations (as may be determined using method
* {@link #inForkJoinPool}). Attempts to invoke in other contexts * {@link #inForkJoinPool}). Attempts to invoke in other contexts
* result in exceptions or errors, possibly including {@code * result in exceptions or errors, possibly including {@code
* ClassCastException}. * ClassCastException}.
@ -529,25 +571,28 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
/** /**
* Attempts to cancel execution of this task. This attempt will * Attempts to cancel execution of this task. This attempt will
* fail if the task has already completed, has already been * fail if the task has already completed or could not be
* cancelled, or could not be cancelled for some other reason. If * cancelled for some other reason. If successful, and this task
* successful, and this task has not started when cancel is * has not started when {@code cancel} is called, execution of
* called, execution of this task is suppressed, {@link * this task is suppressed. After this method returns
* #isCancelled} will report true, and {@link #join} will result * successfully, unless there is an intervening call to {@link
* in a {@code CancellationException} being thrown. * #reinitialize}, subsequent calls to {@link #isCancelled},
* {@link #isDone}, and {@code cancel} will return {@code true}
* and calls to {@link #join} and related methods will result in
* {@code CancellationException}.
* *
* <p>This method may be overridden in subclasses, but if so, must * <p>This method may be overridden in subclasses, but if so, must
* still ensure that these minimal properties hold. In particular, * still ensure that these properties hold. In particular, the
* the {@code cancel} method itself must not throw exceptions. * {@code cancel} method itself must not throw exceptions.
* *
* <p>This method is designed to be invoked by <em>other</em> * <p>This method is designed to be invoked by <em>other</em>
* tasks. To terminate the current task, you can just return or * tasks. To terminate the current task, you can just return or
* throw an unchecked exception from its computation method, or * throw an unchecked exception from its computation method, or
* invoke {@link #completeExceptionally}. * invoke {@link #completeExceptionally}.
* *
* @param mayInterruptIfRunning this value is ignored in the * @param mayInterruptIfRunning this value has no effect in the
* default implementation because tasks are not * default implementation because interrupts are not used to
* cancelled via interruption * control cancellation.
* *
* @return {@code true} if this task is now cancelled * @return {@code true} if this task is now cancelled
*/ */
@ -681,23 +726,13 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* member of a ForkJoinPool and was interrupted while waiting * member of a ForkJoinPool and was interrupted while waiting
*/ */
public final V get() throws InterruptedException, ExecutionException { public final V get() throws InterruptedException, ExecutionException {
int s; Thread t = Thread.currentThread();
if (Thread.currentThread() instanceof ForkJoinWorkerThread) { if (t instanceof ForkJoinWorkerThread)
quietlyJoin(); quietlyJoin();
s = status; else
} externalInterruptibleAwaitDone(false, 0L);
else { int s = status;
while ((s = status) >= 0) { if (s != NORMAL) {
synchronized (this) { // interruptible form of awaitDone
if (UNSAFE.compareAndSwapInt(this, statusOffset,
s, SIGNAL)) {
while (status >= 0)
wait();
}
}
}
}
if (s < NORMAL) {
Throwable ex; Throwable ex;
if (s == CANCELLED) if (s == CANCELLED)
throw new CancellationException(); throw new CancellationException();
@ -723,72 +758,18 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
*/ */
public final V get(long timeout, TimeUnit unit) public final V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException { throws InterruptedException, ExecutionException, TimeoutException {
Thread t = Thread.currentThread();
ForkJoinPool pool;
if (t instanceof ForkJoinWorkerThread) {
ForkJoinWorkerThread w = (ForkJoinWorkerThread) t;
if (status >= 0 && w.unpushTask(this))
quietlyExec();
pool = w.pool;
}
else
pool = null;
/*
* Timed wait loop intermixes cases for FJ (pool != null) and
* non FJ threads. For FJ, decrement pool count but don't try
* for replacement; increment count on completion. For non-FJ,
* deal with interrupts. This is messy, but a little less so
* than is splitting the FJ and nonFJ cases.
*/
boolean interrupted = false;
boolean dec = false; // true if pool count decremented
long nanos = unit.toNanos(timeout); long nanos = unit.toNanos(timeout);
for (;;) { Thread t = Thread.currentThread();
if (pool == null && Thread.interrupted()) { if (t instanceof ForkJoinWorkerThread)
interrupted = true; ((ForkJoinWorkerThread)t).joinTask(this, true, nanos);
break; else
} externalInterruptibleAwaitDone(true, nanos);
int s = status; int s = status;
if (s < 0) if (s != NORMAL) {
break;
if (UNSAFE.compareAndSwapInt(this, statusOffset, s, SIGNAL)) {
long startTime = System.nanoTime();
long nt; // wait time
while (status >= 0 &&
(nt = nanos - (System.nanoTime() - startTime)) > 0) {
if (pool != null && !dec)
dec = pool.tryDecrementRunningCount();
else {
long ms = nt / 1000000;
int ns = (int) (nt % 1000000);
try {
synchronized (this) {
if (status >= 0)
wait(ms, ns);
}
} catch (InterruptedException ie) {
if (pool != null)
cancelIfTerminating();
else {
interrupted = true;
break;
}
}
}
}
break;
}
}
if (pool != null && dec)
pool.incrementRunningCount();
if (interrupted)
throw new InterruptedException();
int es = status;
if (es != NORMAL) {
Throwable ex; Throwable ex;
if (es == CANCELLED) if (s == CANCELLED)
throw new CancellationException(); throw new CancellationException();
if (es == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null) if (s == EXCEPTIONAL && (ex = exceptionMap.get(this)) != null)
throw new ExecutionException(ex); throw new ExecutionException(ex);
throw new TimeoutException(); throw new TimeoutException();
} }
@ -819,7 +800,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
return; return;
} }
} }
w.joinTask(this); w.joinTask(this, false, 0L);
} }
} }
else else
@ -855,7 +836,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* processed. * processed.
* *
* <p>This method may be invoked only from within {@code * <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method * ForkJoinPool} computations (as may be determined using method
* {@link #inForkJoinPool}). Attempts to invoke in other contexts * {@link #inForkJoinPool}). Attempts to invoke in other contexts
* result in exceptions or errors, possibly including {@code * result in exceptions or errors, possibly including {@code
* ClassCastException}. * ClassCastException}.
@ -874,6 +855,12 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* under any other usage conditions are not guaranteed. * under any other usage conditions are not guaranteed.
* This method may be useful when executing * This method may be useful when executing
* pre-constructed trees of subtasks in loops. * pre-constructed trees of subtasks in loops.
*
* <p>Upon completion of this method, {@code isDone()} reports
* {@code false}, and {@code getException()} reports {@code
* null}. However, the value returned by {@code getRawResult} is
* unaffected. To clear this value, you can invoke {@code
* setRawResult(null)}.
*/ */
public void reinitialize() { public void reinitialize() {
if (status == EXCEPTIONAL) if (status == EXCEPTIONAL)
@ -895,11 +882,12 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
} }
/** /**
* Returns {@code true} if the current thread is executing as a * Returns {@code true} if the current thread is a {@link
* ForkJoinPool computation. * ForkJoinWorkerThread} executing as a ForkJoinPool computation.
* *
* @return {@code true} if the current thread is executing as a * @return {@code true} if the current thread is a {@link
* ForkJoinPool computation, or false otherwise * ForkJoinWorkerThread} executing as a ForkJoinPool computation,
* or {@code false} otherwise
*/ */
public static boolean inForkJoinPool() { public static boolean inForkJoinPool() {
return Thread.currentThread() instanceof ForkJoinWorkerThread; return Thread.currentThread() instanceof ForkJoinWorkerThread;
@ -914,7 +902,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* were not, stolen. * were not, stolen.
* *
* <p>This method may be invoked only from within {@code * <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method * ForkJoinPool} computations (as may be determined using method
* {@link #inForkJoinPool}). Attempts to invoke in other contexts * {@link #inForkJoinPool}). Attempts to invoke in other contexts
* result in exceptions or errors, possibly including {@code * result in exceptions or errors, possibly including {@code
* ClassCastException}. * ClassCastException}.
@ -933,7 +921,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* fork other tasks. * fork other tasks.
* *
* <p>This method may be invoked only from within {@code * <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method * ForkJoinPool} computations (as may be determined using method
* {@link #inForkJoinPool}). Attempts to invoke in other contexts * {@link #inForkJoinPool}). Attempts to invoke in other contexts
* result in exceptions or errors, possibly including {@code * result in exceptions or errors, possibly including {@code
* ClassCastException}. * ClassCastException}.
@ -956,7 +944,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* exceeded. * exceeded.
* *
* <p>This method may be invoked only from within {@code * <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method * ForkJoinPool} computations (as may be determined using method
* {@link #inForkJoinPool}). Attempts to invoke in other contexts * {@link #inForkJoinPool}). Attempts to invoke in other contexts
* result in exceptions or errors, possibly including {@code * result in exceptions or errors, possibly including {@code
* ClassCastException}. * ClassCastException}.
@ -1014,7 +1002,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* otherwise. * otherwise.
* *
* <p>This method may be invoked only from within {@code * <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method * ForkJoinPool} computations (as may be determined using method
* {@link #inForkJoinPool}). Attempts to invoke in other contexts * {@link #inForkJoinPool}). Attempts to invoke in other contexts
* result in exceptions or errors, possibly including {@code * result in exceptions or errors, possibly including {@code
* ClassCastException}. * ClassCastException}.
@ -1033,7 +1021,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* be useful otherwise. * be useful otherwise.
* *
* <p>This method may be invoked only from within {@code * <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method * ForkJoinPool} computations (as may be determined using method
* {@link #inForkJoinPool}). Attempts to invoke in other contexts * {@link #inForkJoinPool}). Attempts to invoke in other contexts
* result in exceptions or errors, possibly including {@code * result in exceptions or errors, possibly including {@code
* ClassCastException}. * ClassCastException}.
@ -1056,7 +1044,7 @@ public abstract class ForkJoinTask<V> implements Future<V>, Serializable {
* otherwise. * otherwise.
* *
* <p>This method may be invoked only from within {@code * <p>This method may be invoked only from within {@code
* ForkJoinTask} computations (as may be determined using method * ForkJoinPool} computations (as may be determined using method
* {@link #inForkJoinPool}). Attempts to invoke in other contexts * {@link #inForkJoinPool}). Attempts to invoke in other contexts
* result in exceptions or errors, possibly including {@code * result in exceptions or errors, possibly including {@code
* ClassCastException}. * ClassCastException}.

View File

@ -38,16 +38,18 @@ package java.util.concurrent;
import java.util.Random; import java.util.Random;
import java.util.Collection; import java.util.Collection;
import java.util.concurrent.locks.LockSupport; import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.RejectedExecutionException;
/** /**
* A thread managed by a {@link ForkJoinPool}. This class is * A thread managed by a {@link ForkJoinPool}, which executes
* subclassable solely for the sake of adding functionality -- there * {@link ForkJoinTask}s.
* are no overridable methods dealing with scheduling or execution. * This class is subclassable solely for the sake of adding
* However, you can override initialization and termination methods * functionality -- there are no overridable methods dealing with
* surrounding the main task processing loop. If you do create such a * scheduling or execution. However, you can override initialization
* subclass, you will also need to supply a custom {@link * and termination methods surrounding the main task processing loop.
* ForkJoinPool.ForkJoinWorkerThreadFactory} to use it in a {@code * If you do create such a subclass, you will also need to supply a
* ForkJoinPool}. * custom {@link ForkJoinPool.ForkJoinWorkerThreadFactory} to use it
* in a {@code ForkJoinPool}.
* *
* @since 1.7 * @since 1.7
* @author Doug Lea * @author Doug Lea
@ -376,7 +378,7 @@ public class ForkJoinWorkerThread extends Thread {
/** /**
* Initializes internal state after construction but before * Initializes internal state after construction but before
* processing any tasks. If you override this method, you must * processing any tasks. If you override this method, you must
* invoke @code{super.onStart()} at the beginning of the method. * invoke {@code super.onStart()} at the beginning of the method.
* Initialization requires care: Most fields must have legal * Initialization requires care: Most fields must have legal
* default values, to ensure that attempted accesses from other * default values, to ensure that attempted accesses from other
* threads work correctly even before this thread starts * threads work correctly even before this thread starts
@ -384,7 +386,7 @@ public class ForkJoinWorkerThread extends Thread {
*/ */
protected void onStart() { protected void onStart() {
int rs = seedGenerator.nextInt(); int rs = seedGenerator.nextInt();
seed = rs == 0? 1 : rs; // seed must be nonzero seed = (rs == 0) ? 1 : rs; // seed must be nonzero
// Allocate name string and arrays in this thread // Allocate name string and arrays in this thread
String pid = Integer.toString(pool.getPoolNumber()); String pid = Integer.toString(pool.getPoolNumber());
@ -426,7 +428,7 @@ public class ForkJoinWorkerThread extends Thread {
/** /**
* This method is required to be public, but should never be * This method is required to be public, but should never be
* called explicitly. It performs the main run loop to execute * called explicitly. It performs the main run loop to execute
* ForkJoinTasks. * {@link ForkJoinTask}s.
*/ */
public void run() { public void run() {
Throwable exception = null; Throwable exception = null;
@ -628,6 +630,19 @@ public class ForkJoinWorkerThread extends Thread {
if (t == null) // lost to stealer if (t == null) // lost to stealer
break; break;
if (UNSAFE.compareAndSwapObject(q, u, t, null)) { if (UNSAFE.compareAndSwapObject(q, u, t, null)) {
/*
* Note: here and in related methods, as a
* performance (not correctness) issue, we'd like
* to encourage compiler not to arbitrarily
* postpone setting sp after successful CAS.
* Currently there is no intrinsic for arranging
* this, but using Unsafe putOrderedInt may be a
* preferable strategy on some compilers even
* though its main effect is a pre-, not post-
* fence. To simplify possible changes, the option
* is left in comments next to the associated
* assignments.
*/
sp = s; // putOrderedInt may encourage more timely write sp = s; // putOrderedInt may encourage more timely write
// UNSAFE.putOrderedInt(this, spOffset, s); // UNSAFE.putOrderedInt(this, spOffset, s);
return t; return t;
@ -777,10 +792,10 @@ public class ForkJoinWorkerThread extends Thread {
// Run State management // Run State management
// status check methods used mainly by ForkJoinPool // status check methods used mainly by ForkJoinPool
final boolean isRunning() { return runState == 0; } final boolean isRunning() { return runState == 0; }
final boolean isTerminated() { return (runState & TERMINATED) != 0; } final boolean isTerminated() { return (runState & TERMINATED) != 0; }
final boolean isSuspended() { return (runState & SUSPENDED) != 0; } final boolean isSuspended() { return (runState & SUSPENDED) != 0; }
final boolean isTrimmed() { return (runState & TRIMMED) != 0; } final boolean isTrimmed() { return (runState & TRIMMED) != 0; }
final boolean isTerminating() { final boolean isTerminating() {
if ((runState & TERMINATING) != 0) if ((runState & TERMINATING) != 0)
@ -884,8 +899,7 @@ public class ForkJoinWorkerThread extends Thread {
*/ */
final void cancelTasks() { final void cancelTasks() {
ForkJoinTask<?> cj = currentJoin; // try to cancel ongoing tasks ForkJoinTask<?> cj = currentJoin; // try to cancel ongoing tasks
if (cj != null) { if (cj != null && cj.status >= 0) {
currentJoin = null;
cj.cancelIgnoringExceptions(); cj.cancelIgnoringExceptions();
try { try {
this.interrupt(); // awaken wait this.interrupt(); // awaken wait
@ -893,10 +907,8 @@ public class ForkJoinWorkerThread extends Thread {
} }
} }
ForkJoinTask<?> cs = currentSteal; ForkJoinTask<?> cs = currentSteal;
if (cs != null) { if (cs != null && cs.status >= 0)
currentSteal = null;
cs.cancelIgnoringExceptions(); cs.cancelIgnoringExceptions();
}
while (base != sp) { while (base != sp) {
ForkJoinTask<?> t = deqTask(); ForkJoinTask<?> t = deqTask();
if (t != null) if (t != null)
@ -959,57 +971,23 @@ public class ForkJoinWorkerThread extends Thread {
* Possibly runs some tasks and/or blocks, until task is done. * Possibly runs some tasks and/or blocks, until task is done.
* *
* @param joinMe the task to join * @param joinMe the task to join
* @param timed true if use timed wait
* @param nanos wait time if timed
*/ */
final void joinTask(ForkJoinTask<?> joinMe) { final void joinTask(ForkJoinTask<?> joinMe, boolean timed, long nanos) {
// currentJoin only written by this thread; only need ordered store // currentJoin only written by this thread; only need ordered store
ForkJoinTask<?> prevJoin = currentJoin; ForkJoinTask<?> prevJoin = currentJoin;
UNSAFE.putOrderedObject(this, currentJoinOffset, joinMe); UNSAFE.putOrderedObject(this, currentJoinOffset, joinMe);
if (sp != base) pool.awaitJoin(joinMe, this, timed, nanos);
localHelpJoinTask(joinMe);
if (joinMe.status >= 0)
pool.awaitJoin(joinMe, this);
UNSAFE.putOrderedObject(this, currentJoinOffset, prevJoin); UNSAFE.putOrderedObject(this, currentJoinOffset, prevJoin);
} }
/** /**
* Run tasks in local queue until given task is done. * Tries to locate and help perform tasks for a stealer of the
* * given task, or in turn one of its stealers. Traces
* @param joinMe the task to join * currentSteal->currentJoin links looking for a thread working on
*/ * a descendant of the given task and with a non-empty queue to
private void localHelpJoinTask(ForkJoinTask<?> joinMe) { * steal back and execute tasks from.
int s;
ForkJoinTask<?>[] q;
while (joinMe.status >= 0 && (s = sp) != base && (q = queue) != null) {
int i = (q.length - 1) & --s;
long u = (i << qShift) + qBase; // raw offset
ForkJoinTask<?> t = q[i];
if (t == null) // lost to a stealer
break;
if (UNSAFE.compareAndSwapObject(q, u, t, null)) {
/*
* This recheck (and similarly in helpJoinTask)
* handles cases where joinMe is independently
* cancelled or forced even though there is other work
* available. Back out of the pop by putting t back
* into slot before we commit by writing sp.
*/
if (joinMe.status < 0) {
UNSAFE.putObjectVolatile(q, u, t);
break;
}
sp = s;
// UNSAFE.putOrderedInt(this, spOffset, s);
t.quietlyExec();
}
}
}
/**
* Unless terminating, tries to locate and help perform tasks for
* a stealer of the given task, or in turn one of its stealers.
* Traces currentSteal->currentJoin links looking for a thread
* working on a descendant of the given task and with a non-empty
* queue to steal back and execute tasks from.
* *
* The implementation is very branchy to cope with potential * The implementation is very branchy to cope with potential
* inconsistencies or loops encountering chains that are stale, * inconsistencies or loops encountering chains that are stale,
@ -1019,77 +997,127 @@ public class ForkJoinWorkerThread extends Thread {
* don't work out. * don't work out.
* *
* @param joinMe the task to join * @param joinMe the task to join
* @param running if false, then must update pool count upon
* running a task
* @return value of running on exit
*/ */
final void helpJoinTask(ForkJoinTask<?> joinMe) { final boolean helpJoinTask(ForkJoinTask<?> joinMe, boolean running) {
ForkJoinWorkerThread[] ws; /*
int n; * Initial checks to (1) abort if terminating; (2) clean out
if (joinMe.status < 0) // already done * old cancelled tasks from local queue; (3) if joinMe is next
return; * task, run it; (4) omit scan if local queue nonempty (since
if ((runState & TERMINATING) != 0) { // cancel if shutting down * it may contain non-descendents of joinMe).
joinMe.cancelIgnoringExceptions(); */
return; ForkJoinPool p = pool;
for (;;) {
ForkJoinTask<?>[] q;
int s;
if (joinMe.status < 0)
return running;
else if ((runState & TERMINATING) != 0) {
joinMe.cancelIgnoringExceptions();
return running;
}
else if ((s = sp) == base || (q = queue) == null)
break; // queue empty
else {
int i = (q.length - 1) & --s;
long u = (i << qShift) + qBase; // raw offset
ForkJoinTask<?> t = q[i];
if (t == null)
break; // lost to a stealer
else if (t != joinMe && t.status >= 0)
return running; // cannot safely help
else if ((running ||
(running = p.tryIncrementRunningCount())) &&
UNSAFE.compareAndSwapObject(q, u, t, null)) {
sp = s; // putOrderedInt may encourage more timely write
// UNSAFE.putOrderedInt(this, spOffset, s);
t.quietlyExec();
}
}
} }
if ((ws = pool.workers) == null || (n = ws.length) <= 1)
return; // need at least 2 workers
ForkJoinTask<?> task = joinMe; // base of chain int n; // worker array size
ForkJoinWorkerThread thread = this; // thread with stolen task ForkJoinWorkerThread[] ws = p.workers;
for (int d = 0; d < MAX_HELP_DEPTH; ++d) { // chain length if (ws != null && (n = ws.length) > 1) { // need at least 2 workers
// Try to find v, the stealer of task, by first using hint ForkJoinTask<?> task = joinMe; // base of chain
ForkJoinWorkerThread v = ws[thread.stealHint & (n - 1)]; ForkJoinWorkerThread thread = this; // thread with stolen task
if (v == null || v.currentSteal != task) {
for (int j = 0; ; ++j) { // search array outer:for (int d = 0; d < MAX_HELP_DEPTH; ++d) { // chain length
if (j < n) { // Try to find v, the stealer of task, by first using hint
ForkJoinTask<?> vs; ForkJoinWorkerThread v = ws[thread.stealHint & (n - 1)];
if ((v = ws[j]) != null && if (v == null || v.currentSteal != task) {
(vs = v.currentSteal) != null) { for (int j = 0; ; ++j) { // search array
if (joinMe.status < 0 || task.status < 0) if (j < n) {
return; // stale or done ForkJoinTask<?> vs;
if (vs == task) { if ((v = ws[j]) != null &&
thread.stealHint = j; (vs = v.currentSteal) != null) {
break; // save hint for next time if (joinMe.status < 0)
break outer;
if (vs == task) {
if (task.status < 0)
break outer; // stale
thread.stealHint = j;
break; // save hint for next time
}
} }
} }
else
break outer; // no stealer
} }
else
return; // no stealer
} }
}
for (;;) { // Try to help v, using specialized form of deqTask // Try to help v, using specialized form of deqTask
if (joinMe.status < 0) for (;;) {
return; if (joinMe.status < 0)
int b = v.base; break outer;
ForkJoinTask<?>[] q = v.queue; int b = v.base;
if (b == v.sp || q == null) ForkJoinTask<?>[] q = v.queue;
break; if (b == v.sp || q == null)
int i = (q.length - 1) & b; break; // empty
long u = (i << qShift) + qBase; int i = (q.length - 1) & b;
ForkJoinTask<?> t = q[i]; long u = (i << qShift) + qBase;
int pid = poolIndex; ForkJoinTask<?> t = q[i];
ForkJoinTask<?> ps = currentSteal; if (task.status < 0)
if (task.status < 0) break outer; // stale
return; // stale or done if (t != null &&
if (t != null && v.base == b++ && (running ||
UNSAFE.compareAndSwapObject(q, u, t, null)) { (running = p.tryIncrementRunningCount())) &&
if (joinMe.status < 0) { v.base == b++ &&
UNSAFE.putObjectVolatile(q, u, t); UNSAFE.compareAndSwapObject(q, u, t, null)) {
return; // back out on cancel if (t != joinMe && joinMe.status < 0) {
UNSAFE.putObjectVolatile(q, u, t);
break outer; // joinMe cancelled; back out
}
v.base = b;
if (t.status >= 0) {
ForkJoinTask<?> ps = currentSteal;
int pid = poolIndex;
v.stealHint = pid;
UNSAFE.putOrderedObject(this,
currentStealOffset, t);
t.quietlyExec();
UNSAFE.putOrderedObject(this,
currentStealOffset, ps);
}
}
else if ((runState & TERMINATING) != 0) {
joinMe.cancelIgnoringExceptions();
break outer;
} }
v.base = b;
v.stealHint = pid;
UNSAFE.putOrderedObject(this, currentStealOffset, t);
t.quietlyExec();
UNSAFE.putOrderedObject(this, currentStealOffset, ps);
} }
// Try to descend to find v's stealer
ForkJoinTask<?> next = v.currentJoin;
if (task.status < 0 || next == null || next == task ||
joinMe.status < 0)
break; // done, stale, dead-end, or cyclic
task = next;
thread = v;
} }
// Try to descend to find v's stealer
ForkJoinTask<?> next = v.currentJoin;
if (task.status < 0 || next == null || next == task ||
joinMe.status < 0)
return;
task = next;
thread = v;
} }
return running;
} }
/** /**

View File

@ -1029,6 +1029,8 @@ public class LinkedBlockingDeque<E>
* elements as they existed upon construction of the iterator, and * elements as they existed upon construction of the iterator, and
* may (but is not guaranteed to) reflect any modifications * may (but is not guaranteed to) reflect any modifications
* subsequent to construction. * subsequent to construction.
*
* @return an iterator over the elements in this deque in reverse order
*/ */
public Iterator<E> descendingIterator() { public Iterator<E> descendingIterator() {
return new DescendingItr(); return new DescendingItr();

View File

@ -189,14 +189,14 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
} }
/** /**
* Creates a node and links it at end of queue. * Links node at end of queue.
* *
* @param x the item * @param node the node
*/ */
private void enqueue(E x) { private void enqueue(Node<E> node) {
// assert putLock.isHeldByCurrentThread(); // assert putLock.isHeldByCurrentThread();
// assert last.next == null; // assert last.next == null;
last = last.next = new Node<E>(x); last = last.next = node;
} }
/** /**
@ -282,7 +282,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
throw new NullPointerException(); throw new NullPointerException();
if (n == capacity) if (n == capacity)
throw new IllegalStateException("Queue full"); throw new IllegalStateException("Queue full");
enqueue(e); enqueue(new Node<E>(e));
++n; ++n;
} }
count.set(n); count.set(n);
@ -332,6 +332,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
// Note: convention in all put/take/etc is to preset local var // Note: convention in all put/take/etc is to preset local var
// holding count negative to indicate failure unless set. // holding count negative to indicate failure unless set.
int c = -1; int c = -1;
Node<E> node = new Node(e);
final ReentrantLock putLock = this.putLock; final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count; final AtomicInteger count = this.count;
putLock.lockInterruptibly(); putLock.lockInterruptibly();
@ -347,7 +348,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
while (count.get() == capacity) { while (count.get() == capacity) {
notFull.await(); notFull.await();
} }
enqueue(e); enqueue(node);
c = count.getAndIncrement(); c = count.getAndIncrement();
if (c + 1 < capacity) if (c + 1 < capacity)
notFull.signal(); notFull.signal();
@ -382,7 +383,7 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
return false; return false;
nanos = notFull.awaitNanos(nanos); nanos = notFull.awaitNanos(nanos);
} }
enqueue(e); enqueue(new Node<E>(e));
c = count.getAndIncrement(); c = count.getAndIncrement();
if (c + 1 < capacity) if (c + 1 < capacity)
notFull.signal(); notFull.signal();
@ -411,11 +412,12 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
if (count.get() == capacity) if (count.get() == capacity)
return false; return false;
int c = -1; int c = -1;
Node<E> node = new Node(e);
final ReentrantLock putLock = this.putLock; final ReentrantLock putLock = this.putLock;
putLock.lock(); putLock.lock();
try { try {
if (count.get() < capacity) { if (count.get() < capacity) {
enqueue(e); enqueue(node);
c = count.getAndIncrement(); c = count.getAndIncrement();
if (c + 1 < capacity) if (c + 1 < capacity)
notFull.signal(); notFull.signal();
@ -559,6 +561,27 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
} }
} }
/**
* Returns {@code true} if this queue contains the specified element.
* More formally, returns {@code true} if and only if this queue contains
* at least one element {@code e} such that {@code o.equals(e)}.
*
* @param o object to be checked for containment in this queue
* @return {@code true} if this queue contains the specified element
*/
public boolean contains(Object o) {
if (o == null) return false;
fullyLock();
try {
for (Node<E> p = head.next; p != null; p = p.next)
if (o.equals(p.item))
return true;
return false;
} finally {
fullyUnlock();
}
}
/** /**
* Returns an array containing all of the elements in this queue, in * Returns an array containing all of the elements in this queue, in
* proper sequence. * proper sequence.
@ -645,7 +668,20 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
public String toString() { public String toString() {
fullyLock(); fullyLock();
try { try {
return super.toString(); Node<E> p = head.next;
if (p == null)
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
E e = p.item;
sb.append(e == this ? "(this Collection)" : e);
p = p.next;
if (p == null)
return sb.append(']').toString();
sb.append(',').append(' ');
}
} finally { } finally {
fullyUnlock(); fullyUnlock();
} }
@ -727,12 +763,14 @@ public class LinkedBlockingQueue<E> extends AbstractQueue<E>
/** /**
* Returns an iterator over the elements in this queue in proper sequence. * Returns an iterator over the elements in this queue in proper sequence.
* The returned {@code Iterator} is a "weakly consistent" iterator that * The elements will be returned in order from first (head) to last (tail).
*
* <p>The returned iterator is a "weakly consistent" iterator that
* will never throw {@link java.util.ConcurrentModificationException * will never throw {@link java.util.ConcurrentModificationException
* ConcurrentModificationException}, * ConcurrentModificationException}, and guarantees to traverse
* and guarantees to traverse elements as they existed upon * elements as they existed upon construction of the iterator, and
* construction of the iterator, and may (but is not guaranteed to) * may (but is not guaranteed to) reflect any modifications
* reflect any modifications subsequent to construction. * subsequent to construction.
* *
* @return an iterator over the elements in this queue in proper sequence * @return an iterator over the elements in this queue in proper sequence
*/ */

View File

@ -37,10 +37,10 @@ package java.util.concurrent;
import java.util.AbstractQueue; import java.util.AbstractQueue;
import java.util.Collection; import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator; import java.util.Iterator;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport; import java.util.concurrent.locks.LockSupport;
/** /**
@ -450,7 +450,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
} }
final boolean casItem(Object cmp, Object val) { final boolean casItem(Object cmp, Object val) {
// assert cmp == null || cmp.getClass() != Node.class; // assert cmp == null || cmp.getClass() != Node.class;
return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val); return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
} }
@ -516,7 +516,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
* Tries to artificially match a data node -- used by remove. * Tries to artificially match a data node -- used by remove.
*/ */
final boolean tryMatchData() { final boolean tryMatchData() {
// assert isData; // assert isData;
Object x = item; Object x = item;
if (x != null && x != this && casItem(x, null)) { if (x != null && x != this && casItem(x, null)) {
LockSupport.unpark(waiter); LockSupport.unpark(waiter);
@ -569,7 +569,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static <E> E cast(Object item) { static <E> E cast(Object item) {
// assert item == null || item.getClass() != Node.class; // assert item == null || item.getClass() != Node.class;
return (E) item; return (E) item;
} }
@ -588,7 +588,8 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
throw new NullPointerException(); throw new NullPointerException();
Node s = null; // the node to append, if needed Node s = null; // the node to append, if needed
retry: for (;;) { // restart on append race retry:
for (;;) { // restart on append race
for (Node h = head, p = h; p != null;) { // find & match first node for (Node h = head, p = h; p != null;) { // find & match first node
boolean isData = p.isData; boolean isData = p.isData;
@ -599,7 +600,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
if (p.casItem(item, e)) { // match if (p.casItem(item, e)) { // match
for (Node q = p; q != h;) { for (Node q = p; q != h;) {
Node n = q.next; // update by 2 unless singleton Node n = q.next; // update by 2 unless singleton
if (head == h && casHead(h, n == null? q : n)) { if (head == h && casHead(h, n == null ? q : n)) {
h.forgetNext(); h.forgetNext();
break; break;
} // advance and retry } // advance and retry
@ -684,7 +685,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
for (;;) { for (;;) {
Object item = s.item; Object item = s.item;
if (item != e) { // matched if (item != e) { // matched
// assert item != s; // assert item != s;
s.forgetContents(); // avoid garbage s.forgetContents(); // avoid garbage
return this.<E>cast(item); return this.<E>cast(item);
} }
@ -809,22 +810,61 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
* Moves to next node after prev, or first node if prev null. * Moves to next node after prev, or first node if prev null.
*/ */
private void advance(Node prev) { private void advance(Node prev) {
lastPred = lastRet; /*
lastRet = prev; * To track and avoid buildup of deleted nodes in the face
for (Node p = (prev == null) ? head : succ(prev); * of calls to both Queue.remove and Itr.remove, we must
p != null; p = succ(p)) { * include variants of unsplice and sweep upon each
Object item = p.item; * advance: Upon Itr.remove, we may need to catch up links
if (p.isData) { * from lastPred, and upon other removes, we might need to
if (item != null && item != p) { * skip ahead from stale nodes and unsplice deleted ones
nextItem = LinkedTransferQueue.this.<E>cast(item); * found while advancing.
nextNode = p; */
Node r, b; // reset lastPred upon possible deletion of lastRet
if ((r = lastRet) != null && !r.isMatched())
lastPred = r; // next lastPred is old lastRet
else if ((b = lastPred) == null || b.isMatched())
lastPred = null; // at start of list
else {
Node s, n; // help with removal of lastPred.next
while ((s = b.next) != null &&
s != b && s.isMatched() &&
(n = s.next) != null && n != s)
b.casNext(s, n);
}
this.lastRet = prev;
for (Node p = prev, s, n;;) {
s = (p == null) ? head : p.next;
if (s == null)
break;
else if (s == p) {
p = null;
continue;
}
Object item = s.item;
if (s.isData) {
if (item != null && item != s) {
nextItem = LinkedTransferQueue.<E>cast(item);
nextNode = s;
return; return;
} }
} }
else if (item == null) else if (item == null)
break; break;
// assert s.isMatched();
if (p == null)
p = s;
else if ((n = s.next) == null)
break;
else if (s == n)
p = null;
else
p.casNext(s, n);
} }
nextNode = null; nextNode = null;
nextItem = null;
} }
Itr() { Itr() {
@ -844,10 +884,12 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
} }
public final void remove() { public final void remove() {
Node p = lastRet; final Node lastRet = this.lastRet;
if (p == null) throw new IllegalStateException(); if (lastRet == null)
if (p.tryMatchData()) throw new IllegalStateException();
unsplice(lastPred, p); this.lastRet = null;
if (lastRet.tryMatchData())
unsplice(lastPred, lastRet);
} }
} }
@ -997,8 +1039,7 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
* Inserts the specified element at the tail of this queue. * Inserts the specified element at the tail of this queue.
* As the queue is unbounded, this method will never return {@code false}. * As the queue is unbounded, this method will never return {@code false}.
* *
* @return {@code true} (as specified by * @return {@code true} (as specified by {@link Queue#offer})
* {@link BlockingQueue#offer(Object) BlockingQueue.offer})
* @throws NullPointerException if the specified element is null * @throws NullPointerException if the specified element is null
*/ */
public boolean offer(E e) { public boolean offer(E e) {
@ -1130,15 +1171,15 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
} }
/** /**
* Returns an iterator over the elements in this queue in proper * Returns an iterator over the elements in this queue in proper sequence.
* sequence, from head to tail. * The elements will be returned in order from first (head) to last (tail).
* *
* <p>The returned iterator is a "weakly consistent" iterator that * <p>The returned iterator is a "weakly consistent" iterator that
* will never throw * will never throw {@link java.util.ConcurrentModificationException
* {@link ConcurrentModificationException ConcurrentModificationException}, * ConcurrentModificationException}, and guarantees to traverse
* and guarantees to traverse elements as they existed upon * elements as they existed upon construction of the iterator, and
* construction of the iterator, and may (but is not guaranteed * may (but is not guaranteed to) reflect any modifications
* to) reflect any modifications subsequent to construction. * subsequent to construction.
* *
* @return an iterator over the elements in this queue in proper sequence * @return an iterator over the elements in this queue in proper sequence
*/ */
@ -1202,6 +1243,28 @@ public class LinkedTransferQueue<E> extends AbstractQueue<E>
return findAndRemove(o); return findAndRemove(o);
} }
/**
* Returns {@code true} if this queue contains the specified element.
* More formally, returns {@code true} if and only if this queue contains
* at least one element {@code e} such that {@code o.equals(e)}.
*
* @param o object to be checked for containment in this queue
* @return {@code true} if this queue contains the specified element
*/
public boolean contains(Object o) {
if (o == null) return false;
for (Node p = head; p != null; p = succ(p)) {
Object item = p.item;
if (p.isData) {
if (item != null && item != p && o.equals(item))
return true;
}
else if (item == null)
break;
}
return false;
}
/** /**
* Always returns {@code Integer.MAX_VALUE} because a * Always returns {@code Integer.MAX_VALUE} because a
* {@code LinkedTransferQueue} is not capacity constrained. * {@code LinkedTransferQueue} is not capacity constrained.

File diff suppressed because it is too large Load Diff

View File

@ -43,11 +43,11 @@ import java.util.*;
* the same ordering rules as class {@link PriorityQueue} and supplies * the same ordering rules as class {@link PriorityQueue} and supplies
* blocking retrieval operations. While this queue is logically * blocking retrieval operations. While this queue is logically
* unbounded, attempted additions may fail due to resource exhaustion * unbounded, attempted additions may fail due to resource exhaustion
* (causing <tt>OutOfMemoryError</tt>). This class does not permit * (causing {@code OutOfMemoryError}). This class does not permit
* <tt>null</tt> elements. A priority queue relying on {@linkplain * {@code null} elements. A priority queue relying on {@linkplain
* Comparable natural ordering} also does not permit insertion of * Comparable natural ordering} also does not permit insertion of
* non-comparable objects (doing so results in * non-comparable objects (doing so results in
* <tt>ClassCastException</tt>). * {@code ClassCastException}).
* *
* <p>This class and its iterator implement all of the * <p>This class and its iterator implement all of the
* <em>optional</em> methods of the {@link Collection} and {@link * <em>optional</em> methods of the {@link Collection} and {@link
@ -55,7 +55,7 @@ import java.util.*;
* #iterator()} is <em>not</em> guaranteed to traverse the elements of * #iterator()} is <em>not</em> guaranteed to traverse the elements of
* the PriorityBlockingQueue in any particular order. If you need * the PriorityBlockingQueue in any particular order. If you need
* ordered traversal, consider using * ordered traversal, consider using
* <tt>Arrays.sort(pq.toArray())</tt>. Also, method <tt>drainTo</tt> * {@code Arrays.sort(pq.toArray())}. Also, method {@code drainTo}
* can be used to <em>remove</em> some or all elements in priority * can be used to <em>remove</em> some or all elements in priority
* order and place them in another collection. * order and place them in another collection.
* *
@ -65,12 +65,12 @@ import java.util.*;
* secondary key to break ties in primary priority values. For * secondary key to break ties in primary priority values. For
* example, here is a class that applies first-in-first-out * example, here is a class that applies first-in-first-out
* tie-breaking to comparable elements. To use it, you would insert a * tie-breaking to comparable elements. To use it, you would insert a
* <tt>new FIFOEntry(anEntry)</tt> instead of a plain entry object. * {@code new FIFOEntry(anEntry)} instead of a plain entry object.
* *
* <pre> * <pre> {@code
* class FIFOEntry&lt;E extends Comparable&lt;? super E&gt;&gt; * class FIFOEntry<E extends Comparable<? super E>>
* implements Comparable&lt;FIFOEntry&lt;E&gt;&gt; { * implements Comparable<FIFOEntry<E>> {
* final static AtomicLong seq = new AtomicLong(); * static final AtomicLong seq = new AtomicLong(0);
* final long seqNum; * final long seqNum;
* final E entry; * final E entry;
* public FIFOEntry(E entry) { * public FIFOEntry(E entry) {
@ -78,13 +78,13 @@ import java.util.*;
* this.entry = entry; * this.entry = entry;
* } * }
* public E getEntry() { return entry; } * public E getEntry() { return entry; }
* public int compareTo(FIFOEntry&lt;E&gt; other) { * public int compareTo(FIFOEntry<E> other) {
* int res = entry.compareTo(other.entry); * int res = entry.compareTo(other.entry);
* if (res == 0 &amp;&amp; other.entry != this.entry) * if (res == 0 && other.entry != this.entry)
* res = (seqNum &lt; other.seqNum ? -1 : 1); * res = (seqNum < other.seqNum ? -1 : 1);
* return res; * return res;
* } * }
* }</pre> * }}</pre>
* *
* <p>This class is a member of the * <p>This class is a member of the
* <a href="{@docRoot}/../technotes/guides/collections/index.html"> * <a href="{@docRoot}/../technotes/guides/collections/index.html">
@ -98,34 +98,102 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable { implements BlockingQueue<E>, java.io.Serializable {
private static final long serialVersionUID = 5595510919245408276L; private static final long serialVersionUID = 5595510919245408276L;
private final PriorityQueue<E> q; /*
private final ReentrantLock lock = new ReentrantLock(true); * The implementation uses an array-based binary heap, with public
private final Condition notEmpty = lock.newCondition(); * operations protected with a single lock. However, allocation
* during resizing uses a simple spinlock (used only while not
* holding main lock) in order to allow takes to operate
* concurrently with allocation. This avoids repeated
* postponement of waiting consumers and consequent element
* build-up. The need to back away from lock during allocation
* makes it impossible to simply wrap delegated
* java.util.PriorityQueue operations within a lock, as was done
* in a previous version of this class. To maintain
* interoperability, a plain PriorityQueue is still used during
* serialization, which maintains compatibility at the espense of
* transiently doubling overhead.
*/
/** /**
* Creates a <tt>PriorityBlockingQueue</tt> with the default * Default array capacity.
*/
private static final int DEFAULT_INITIAL_CAPACITY = 11;
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* Priority queue represented as a balanced binary heap: the two
* children of queue[n] are queue[2*n+1] and queue[2*(n+1)]. The
* priority queue is ordered by comparator, or by the elements'
* natural ordering, if comparator is null: For each node n in the
* heap and each descendant d of n, n <= d. The element with the
* lowest value is in queue[0], assuming the queue is nonempty.
*/
private transient Object[] queue;
/**
* The number of elements in the priority queue.
*/
private transient int size;
/**
* The comparator, or null if priority queue uses elements'
* natural ordering.
*/
private transient Comparator<? super E> comparator;
/**
* Lock used for all public operations
*/
private final ReentrantLock lock;
/**
* Condition for blocking when empty
*/
private final Condition notEmpty;
/**
* Spinlock for allocation, acquired via CAS.
*/
private transient volatile int allocationSpinLock;
/**
* A plain PriorityQueue used only for serialization,
* to maintain compatibility with previous versions
* of this class. Non-null only during serialization/deserialization.
*/
private PriorityQueue q;
/**
* Creates a {@code PriorityBlockingQueue} with the default
* initial capacity (11) that orders its elements according to * initial capacity (11) that orders its elements according to
* their {@linkplain Comparable natural ordering}. * their {@linkplain Comparable natural ordering}.
*/ */
public PriorityBlockingQueue() { public PriorityBlockingQueue() {
q = new PriorityQueue<E>(); this(DEFAULT_INITIAL_CAPACITY, null);
} }
/** /**
* Creates a <tt>PriorityBlockingQueue</tt> with the specified * Creates a {@code PriorityBlockingQueue} with the specified
* initial capacity that orders its elements according to their * initial capacity that orders its elements according to their
* {@linkplain Comparable natural ordering}. * {@linkplain Comparable natural ordering}.
* *
* @param initialCapacity the initial capacity for this priority queue * @param initialCapacity the initial capacity for this priority queue
* @throws IllegalArgumentException if <tt>initialCapacity</tt> is less * @throws IllegalArgumentException if {@code initialCapacity} is less
* than 1 * than 1
*/ */
public PriorityBlockingQueue(int initialCapacity) { public PriorityBlockingQueue(int initialCapacity) {
q = new PriorityQueue<E>(initialCapacity, null); this(initialCapacity, null);
} }
/** /**
* Creates a <tt>PriorityBlockingQueue</tt> with the specified initial * Creates a {@code PriorityBlockingQueue} with the specified initial
* capacity that orders its elements according to the specified * capacity that orders its elements according to the specified
* comparator. * comparator.
* *
@ -133,16 +201,21 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
* @param comparator the comparator that will be used to order this * @param comparator the comparator that will be used to order this
* priority queue. If {@code null}, the {@linkplain Comparable * priority queue. If {@code null}, the {@linkplain Comparable
* natural ordering} of the elements will be used. * natural ordering} of the elements will be used.
* @throws IllegalArgumentException if <tt>initialCapacity</tt> is less * @throws IllegalArgumentException if {@code initialCapacity} is less
* than 1 * than 1
*/ */
public PriorityBlockingQueue(int initialCapacity, public PriorityBlockingQueue(int initialCapacity,
Comparator<? super E> comparator) { Comparator<? super E> comparator) {
q = new PriorityQueue<E>(initialCapacity, comparator); if (initialCapacity < 1)
throw new IllegalArgumentException();
this.lock = new ReentrantLock();
this.notEmpty = lock.newCondition();
this.comparator = comparator;
this.queue = new Object[initialCapacity];
} }
/** /**
* Creates a <tt>PriorityBlockingQueue</tt> containing the elements * Creates a {@code PriorityBlockingQueue} containing the elements
* in the specified collection. If the specified collection is a * in the specified collection. If the specified collection is a
* {@link SortedSet} or a {@link PriorityQueue}, this * {@link SortedSet} or a {@link PriorityQueue}, this
* priority queue will be ordered according to the same ordering. * priority queue will be ordered according to the same ordering.
@ -158,14 +231,215 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
* of its elements are null * of its elements are null
*/ */
public PriorityBlockingQueue(Collection<? extends E> c) { public PriorityBlockingQueue(Collection<? extends E> c) {
q = new PriorityQueue<E>(c); this.lock = new ReentrantLock();
this.notEmpty = lock.newCondition();
boolean heapify = true; // true if not known to be in heap order
boolean screen = true; // true if must screen for nulls
if (c instanceof SortedSet<?>) {
SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
this.comparator = (Comparator<? super E>) ss.comparator();
heapify = false;
}
else if (c instanceof PriorityBlockingQueue<?>) {
PriorityBlockingQueue<? extends E> pq =
(PriorityBlockingQueue<? extends E>) c;
this.comparator = (Comparator<? super E>) pq.comparator();
screen = false;
if (pq.getClass() == PriorityBlockingQueue.class) // exact match
heapify = false;
}
Object[] a = c.toArray();
int n = a.length;
// If c.toArray incorrectly doesn't return Object[], copy it.
if (a.getClass() != Object[].class)
a = Arrays.copyOf(a, n, Object[].class);
if (screen && (n == 1 || this.comparator != null)) {
for (int i = 0; i < n; ++i)
if (a[i] == null)
throw new NullPointerException();
}
this.queue = a;
this.size = n;
if (heapify)
heapify();
}
/**
* Tries to grow array to accommodate at least one more element
* (but normally expand by about 50%), giving up (allowing retry)
* on contention (which we expect to be rare). Call only while
* holding lock.
*
* @param array the heap array
* @param oldCap the length of the array
*/
private void tryGrow(Object[] array, int oldCap) {
lock.unlock(); // must release and then re-acquire main lock
Object[] newArray = null;
if (allocationSpinLock == 0 &&
UNSAFE.compareAndSwapInt(this, allocationSpinLockOffset,
0, 1)) {
try {
int newCap = oldCap + ((oldCap < 64) ?
(oldCap + 2) : // grow faster if small
(oldCap >> 1));
if (newCap - MAX_ARRAY_SIZE > 0) { // possible overflow
int minCap = oldCap + 1;
if (minCap < 0 || minCap > MAX_ARRAY_SIZE)
throw new OutOfMemoryError();
newCap = MAX_ARRAY_SIZE;
}
if (newCap > oldCap && queue == array)
newArray = new Object[newCap];
} finally {
allocationSpinLock = 0;
}
}
if (newArray == null) // back off if another thread is allocating
Thread.yield();
lock.lock();
if (newArray != null && queue == array) {
queue = newArray;
System.arraycopy(array, 0, newArray, 0, oldCap);
}
}
/**
* Mechanics for poll(). Call only while holding lock.
*/
private E extract() {
E result;
int n = size - 1;
if (n < 0)
result = null;
else {
Object[] array = queue;
result = (E) array[0];
E x = (E) array[n];
array[n] = null;
Comparator<? super E> cmp = comparator;
if (cmp == null)
siftDownComparable(0, x, array, n);
else
siftDownUsingComparator(0, x, array, n, cmp);
size = n;
}
return result;
}
/**
* Inserts item x at position k, maintaining heap invariant by
* promoting x up the tree until it is greater than or equal to
* its parent, or is the root.
*
* To simplify and speed up coercions and comparisons. the
* Comparable and Comparator versions are separated into different
* methods that are otherwise identical. (Similarly for siftDown.)
* These methods are static, with heap state as arguments, to
* simplify use in light of possible comparator exceptions.
*
* @param k the position to fill
* @param x the item to insert
* @param array the heap array
* @param n heap size
*/
private static <T> void siftUpComparable(int k, T x, Object[] array) {
Comparable<? super T> key = (Comparable<? super T>) x;
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = array[parent];
if (key.compareTo((T) e) >= 0)
break;
array[k] = e;
k = parent;
}
array[k] = key;
}
private static <T> void siftUpUsingComparator(int k, T x, Object[] array,
Comparator<? super T> cmp) {
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = array[parent];
if (cmp.compare(x, (T) e) >= 0)
break;
array[k] = e;
k = parent;
}
array[k] = x;
}
/**
* Inserts item x at position k, maintaining heap invariant by
* demoting x down the tree repeatedly until it is less than or
* equal to its children or is a leaf.
*
* @param k the position to fill
* @param x the item to insert
* @param array the heap array
* @param n heap size
*/
private static <T> void siftDownComparable(int k, T x, Object[] array,
int n) {
Comparable<? super T> key = (Comparable<? super T>)x;
int half = n >>> 1; // loop while a non-leaf
while (k < half) {
int child = (k << 1) + 1; // assume left child is least
Object c = array[child];
int right = child + 1;
if (right < n &&
((Comparable<? super T>) c).compareTo((T) array[right]) > 0)
c = array[child = right];
if (key.compareTo((T) c) <= 0)
break;
array[k] = c;
k = child;
}
array[k] = key;
}
private static <T> void siftDownUsingComparator(int k, T x, Object[] array,
int n,
Comparator<? super T> cmp) {
int half = n >>> 1;
while (k < half) {
int child = (k << 1) + 1;
Object c = array[child];
int right = child + 1;
if (right < n && cmp.compare((T) c, (T) array[right]) > 0)
c = array[child = right];
if (cmp.compare(x, (T) c) <= 0)
break;
array[k] = c;
k = child;
}
array[k] = x;
}
/**
* Establishes the heap invariant (described above) in the entire tree,
* assuming nothing about the order of the elements prior to the call.
*/
private void heapify() {
Object[] array = queue;
int n = size;
int half = (n >>> 1) - 1;
Comparator<? super E> cmp = comparator;
if (cmp == null) {
for (int i = half; i >= 0; i--)
siftDownComparable(i, (E) array[i], array, n);
}
else {
for (int i = half; i >= 0; i--)
siftDownUsingComparator(i, (E) array[i], array, n, cmp);
}
} }
/** /**
* Inserts the specified element into this priority queue. * Inserts the specified element into this priority queue.
* *
* @param e the element to add * @param e the element to add
* @return <tt>true</tt> (as specified by {@link Collection#add}) * @return {@code true} (as specified by {@link Collection#add})
* @throws ClassCastException if the specified element cannot be compared * @throws ClassCastException if the specified element cannot be compared
* with elements currently in the priority queue according to the * with elements currently in the priority queue according to the
* priority queue's ordering * priority queue's ordering
@ -177,30 +451,41 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
/** /**
* Inserts the specified element into this priority queue. * Inserts the specified element into this priority queue.
* As the queue is unbounded, this method will never return {@code false}.
* *
* @param e the element to add * @param e the element to add
* @return <tt>true</tt> (as specified by {@link Queue#offer}) * @return {@code true} (as specified by {@link Queue#offer})
* @throws ClassCastException if the specified element cannot be compared * @throws ClassCastException if the specified element cannot be compared
* with elements currently in the priority queue according to the * with elements currently in the priority queue according to the
* priority queue's ordering * priority queue's ordering
* @throws NullPointerException if the specified element is null * @throws NullPointerException if the specified element is null
*/ */
public boolean offer(E e) { public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
int n, cap;
Object[] array;
while ((n = size) >= (cap = (array = queue).length))
tryGrow(array, cap);
try { try {
boolean ok = q.offer(e); Comparator<? super E> cmp = comparator;
assert ok; if (cmp == null)
siftUpComparable(n, e, array);
else
siftUpUsingComparator(n, e, array, cmp);
size = n + 1;
notEmpty.signal(); notEmpty.signal();
return true;
} finally { } finally {
lock.unlock(); lock.unlock();
} }
return true;
} }
/** /**
* Inserts the specified element into this priority queue. As the queue is * Inserts the specified element into this priority queue.
* unbounded this method will never block. * As the queue is unbounded, this method will never block.
* *
* @param e the element to add * @param e the element to add
* @throws ClassCastException if the specified element cannot be compared * @throws ClassCastException if the specified element cannot be compared
@ -213,13 +498,15 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
} }
/** /**
* Inserts the specified element into this priority queue. As the queue is * Inserts the specified element into this priority queue.
* unbounded this method will never block. * As the queue is unbounded, this method will never block or
* return {@code false}.
* *
* @param e the element to add * @param e the element to add
* @param timeout This parameter is ignored as the method never blocks * @param timeout This parameter is ignored as the method never blocks
* @param unit This parameter is ignored as the method never blocks * @param unit This parameter is ignored as the method never blocks
* @return <tt>true</tt> * @return {@code true} (as specified by
* {@link BlockingQueue#offer(Object,long,TimeUnit) BlockingQueue.offer})
* @throws ClassCastException if the specified element cannot be compared * @throws ClassCastException if the specified element cannot be compared
* with elements currently in the priority queue according to the * with elements currently in the priority queue according to the
* priority queue's ordering * priority queue's ordering
@ -232,97 +519,123 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
public E poll() { public E poll() {
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
E result;
try { try {
return q.poll(); result = extract();
} finally { } finally {
lock.unlock(); lock.unlock();
} }
return result;
} }
public E take() throws InterruptedException { public E take() throws InterruptedException {
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lockInterruptibly(); lock.lockInterruptibly();
E result;
try { try {
try { while ( (result = extract()) == null)
while (q.size() == 0) notEmpty.await();
notEmpty.await();
} catch (InterruptedException ie) {
notEmpty.signal(); // propagate to non-interrupted thread
throw ie;
}
E x = q.poll();
assert x != null;
return x;
} finally { } finally {
lock.unlock(); lock.unlock();
} }
return result;
} }
public E poll(long timeout, TimeUnit unit) throws InterruptedException { public E poll(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout); long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lockInterruptibly(); lock.lockInterruptibly();
E result;
try { try {
for (;;) { while ( (result = extract()) == null && nanos > 0)
E x = q.poll(); nanos = notEmpty.awaitNanos(nanos);
if (x != null)
return x;
if (nanos <= 0)
return null;
try {
nanos = notEmpty.awaitNanos(nanos);
} catch (InterruptedException ie) {
notEmpty.signal(); // propagate to non-interrupted thread
throw ie;
}
}
} finally { } finally {
lock.unlock(); lock.unlock();
} }
return result;
} }
public E peek() { public E peek() {
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
E result;
try { try {
return q.peek(); result = size > 0 ? (E) queue[0] : null;
} finally { } finally {
lock.unlock(); lock.unlock();
} }
return result;
} }
/** /**
* Returns the comparator used to order the elements in this queue, * Returns the comparator used to order the elements in this queue,
* or <tt>null</tt> if this queue uses the {@linkplain Comparable * or {@code null} if this queue uses the {@linkplain Comparable
* natural ordering} of its elements. * natural ordering} of its elements.
* *
* @return the comparator used to order the elements in this queue, * @return the comparator used to order the elements in this queue,
* or <tt>null</tt> if this queue uses the natural * or {@code null} if this queue uses the natural
* ordering of its elements * ordering of its elements
*/ */
public Comparator<? super E> comparator() { public Comparator<? super E> comparator() {
return q.comparator(); return comparator;
} }
public int size() { public int size() {
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
return q.size(); return size;
} finally { } finally {
lock.unlock(); lock.unlock();
} }
} }
/** /**
* Always returns <tt>Integer.MAX_VALUE</tt> because * Always returns {@code Integer.MAX_VALUE} because
* a <tt>PriorityBlockingQueue</tt> is not capacity constrained. * a {@code PriorityBlockingQueue} is not capacity constrained.
* @return <tt>Integer.MAX_VALUE</tt> * @return {@code Integer.MAX_VALUE} always
*/ */
public int remainingCapacity() { public int remainingCapacity() {
return Integer.MAX_VALUE; return Integer.MAX_VALUE;
} }
private int indexOf(Object o) {
if (o != null) {
Object[] array = queue;
int n = size;
for (int i = 0; i < n; i++)
if (o.equals(array[i]))
return i;
}
return -1;
}
/**
* Removes the ith element from queue.
*/
private void removeAt(int i) {
Object[] array = queue;
int n = size - 1;
if (n == i) // removed last element
array[i] = null;
else {
E moved = (E) array[n];
array[n] = null;
Comparator<? super E> cmp = comparator;
if (cmp == null)
siftDownComparable(i, moved, array, n);
else
siftDownUsingComparator(i, moved, array, n, cmp);
if (array[i] == moved) {
if (cmp == null)
siftUpComparable(i, moved, array);
else
siftUpUsingComparator(i, moved, array, cmp);
}
}
size = n;
}
/** /**
* Removes a single instance of the specified element from this queue, * Removes a single instance of the specified element from this queue,
* if it is present. More formally, removes an element {@code e} such * if it is present. More formally, removes an element {@code e} such
@ -332,13 +645,40 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
* result of the call). * result of the call).
* *
* @param o element to be removed from this queue, if present * @param o element to be removed from this queue, if present
* @return <tt>true</tt> if this queue changed as a result of the call * @return {@code true} if this queue changed as a result of the call
*/ */
public boolean remove(Object o) { public boolean remove(Object o) {
boolean removed = false;
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
return q.remove(o); int i = indexOf(o);
if (i != -1) {
removeAt(i);
removed = true;
}
} finally {
lock.unlock();
}
return removed;
}
/**
* Identity-based version for use in Itr.remove
*/
private void removeEQ(Object o) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] array = queue;
int n = size;
for (int i = 0; i < n; i++) {
if (o == array[i]) {
removeAt(i);
break;
}
}
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@ -350,16 +690,18 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
* at least one element {@code e} such that {@code o.equals(e)}. * at least one element {@code e} such that {@code o.equals(e)}.
* *
* @param o object to be checked for containment in this queue * @param o object to be checked for containment in this queue
* @return <tt>true</tt> if this queue contains the specified element * @return {@code true} if this queue contains the specified element
*/ */
public boolean contains(Object o) { public boolean contains(Object o) {
int index;
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
return q.contains(o); index = indexOf(o);
} finally { } finally {
lock.unlock(); lock.unlock();
} }
return index != -1;
} }
/** /**
@ -379,7 +721,7 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
return q.toArray(); return Arrays.copyOf(queue, size);
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@ -390,7 +732,18 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
return q.toString(); int n = size;
if (n == 0)
return "[]";
StringBuilder sb = new StringBuilder();
sb.append('[');
for (int i = 0; i < n; ++i) {
E e = (E)queue[i];
sb.append(e == this ? "(this Collection)" : e);
if (i != n - 1)
sb.append(',').append(' ');
}
return sb.append(']').toString();
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@ -412,7 +765,7 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
try { try {
int n = 0; int n = 0;
E e; E e;
while ( (e = q.poll()) != null) { while ( (e = extract()) != null) {
c.add(e); c.add(e);
++n; ++n;
} }
@ -440,7 +793,7 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
try { try {
int n = 0; int n = 0;
E e; E e;
while (n < maxElements && (e = q.poll()) != null) { while (n < maxElements && (e = extract()) != null) {
c.add(e); c.add(e);
++n; ++n;
} }
@ -458,7 +811,11 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
q.clear(); Object[] array = queue;
int n = size;
size = 0;
for (int i = 0; i < n; i++)
array[i] = null;
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@ -475,22 +832,22 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
* <p>If this queue fits in the specified array with room to spare * <p>If this queue fits in the specified array with room to spare
* (i.e., the array has more elements than this queue), the element in * (i.e., the array has more elements than this queue), the element in
* the array immediately following the end of the queue is set to * the array immediately following the end of the queue is set to
* <tt>null</tt>. * {@code null}.
* *
* <p>Like the {@link #toArray()} method, this method acts as bridge between * <p>Like the {@link #toArray()} method, this method acts as bridge between
* array-based and collection-based APIs. Further, this method allows * array-based and collection-based APIs. Further, this method allows
* precise control over the runtime type of the output array, and may, * precise control over the runtime type of the output array, and may,
* under certain circumstances, be used to save allocation costs. * under certain circumstances, be used to save allocation costs.
* *
* <p>Suppose <tt>x</tt> is a queue known to contain only strings. * <p>Suppose {@code x} is a queue known to contain only strings.
* The following code can be used to dump the queue into a newly * The following code can be used to dump the queue into a newly
* allocated array of <tt>String</tt>: * allocated array of {@code String}:
* *
* <pre> * <pre>
* String[] y = x.toArray(new String[0]);</pre> * String[] y = x.toArray(new String[0]);</pre>
* *
* Note that <tt>toArray(new Object[0])</tt> is identical in function to * Note that {@code toArray(new Object[0])} is identical in function to
* <tt>toArray()</tt>. * {@code toArray()}.
* *
* @param a the array into which the elements of the queue are to * @param a the array into which the elements of the queue are to
* be stored, if it is big enough; otherwise, a new array of the * be stored, if it is big enough; otherwise, a new array of the
@ -505,7 +862,14 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
final ReentrantLock lock = this.lock; final ReentrantLock lock = this.lock;
lock.lock(); lock.lock();
try { try {
return q.toArray(a); int n = size;
if (a.length < n)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(queue, size, a.getClass());
System.arraycopy(queue, 0, a, 0, n);
if (a.length > n)
a[n] = null;
return a;
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@ -514,8 +878,9 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
/** /**
* Returns an iterator over the elements in this queue. The * Returns an iterator over the elements in this queue. The
* iterator does not return the elements in any particular order. * iterator does not return the elements in any particular order.
* The returned <tt>Iterator</tt> is a "weakly consistent" *
* iterator that will never throw {@link * <p>The returned iterator is a "weakly consistent" iterator that
* will never throw {@link java.util.ConcurrentModificationException
* ConcurrentModificationException}, and guarantees to traverse * ConcurrentModificationException}, and guarantees to traverse
* elements as they existed upon construction of the iterator, and * elements as they existed upon construction of the iterator, and
* may (but is not guaranteed to) reflect any modifications * may (but is not guaranteed to) reflect any modifications
@ -530,7 +895,7 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
/** /**
* Snapshot iterator that works off copy of underlying q array. * Snapshot iterator that works off copy of underlying q array.
*/ */
private class Itr implements Iterator<E> { final class Itr implements Iterator<E> {
final Object[] array; // Array of all elements final Object[] array; // Array of all elements
int cursor; // index of next element to return; int cursor; // index of next element to return;
int lastRet; // index of last element, or -1 if no such int lastRet; // index of last element, or -1 if no such
@ -554,39 +919,65 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
public void remove() { public void remove() {
if (lastRet < 0) if (lastRet < 0)
throw new IllegalStateException(); throw new IllegalStateException();
Object x = array[lastRet]; removeEQ(array[lastRet]);
lastRet = -1; lastRet = -1;
// Traverse underlying queue to find == element,
// not just a .equals element.
lock.lock();
try {
for (Iterator it = q.iterator(); it.hasNext(); ) {
if (it.next() == x) {
it.remove();
return;
}
}
} finally {
lock.unlock();
}
} }
} }
/** /**
* Saves the state to a stream (that is, serializes it). This * Saves the state to a stream (that is, serializes it). For
* merely wraps default serialization within lock. The * compatibility with previous version of this class,
* serialization strategy for items is left to underlying * elements are first copied to a java.util.PriorityQueue,
* Queue. Note that locking is not needed on deserialization, so * which is then serialized.
* readObject is not defined, just relying on default.
*/ */
private void writeObject(java.io.ObjectOutputStream s) private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException { throws java.io.IOException {
lock.lock(); lock.lock();
try { try {
int n = size; // avoid zero capacity argument
q = new PriorityQueue<E>(n == 0 ? 1 : n, comparator);
q.addAll(this);
s.defaultWriteObject(); s.defaultWriteObject();
} finally { } finally {
q = null;
lock.unlock(); lock.unlock();
} }
} }
/**
* Reconstitutes the {@code PriorityBlockingQueue} instance from a stream
* (that is, deserializes it).
*
* @param s the stream
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
try {
s.defaultReadObject();
this.queue = new Object[q.size()];
comparator = q.comparator();
addAll(q);
} finally {
q = null;
}
}
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long allocationSpinLockOffset =
objectFieldOffset(UNSAFE, "allocationSpinLock",
PriorityBlockingQueue.class);
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
String field, Class<?> klazz) {
try {
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
} catch (NoSuchFieldException e) {
// Convert Exception to corresponding Error
NoSuchFieldError error = new NoSuchFieldError(field);
error.initCause(e);
throw error;
}
}
} }

View File

@ -360,8 +360,12 @@ public class ScheduledThreadPoolExecutor
getExecuteExistingDelayedTasksAfterShutdownPolicy(); getExecuteExistingDelayedTasksAfterShutdownPolicy();
boolean keepPeriodic = boolean keepPeriodic =
getContinueExistingPeriodicTasksAfterShutdownPolicy(); getContinueExistingPeriodicTasksAfterShutdownPolicy();
if (!keepDelayed && !keepPeriodic) if (!keepDelayed && !keepPeriodic) {
for (Object e : q.toArray())
if (e instanceof RunnableScheduledFuture<?>)
((RunnableScheduledFuture<?>) e).cancel(false);
q.clear(); q.clear();
}
else { else {
// Traverse snapshot to avoid iterator exceptions // Traverse snapshot to avoid iterator exceptions
for (Object e : q.toArray()) { for (Object e : q.toArray()) {

View File

@ -163,7 +163,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
/** /**
* Shared internal API for dual stacks and queues. * Shared internal API for dual stacks and queues.
*/ */
static abstract class Transferer { abstract static class Transferer {
/** /**
* Performs a put or take. * Performs a put or take.
* *
@ -190,7 +190,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
* seems not to vary with number of CPUs (beyond 2) so is just * seems not to vary with number of CPUs (beyond 2) so is just
* a constant. * a constant.
*/ */
static final int maxTimedSpins = (NCPUS < 2)? 0 : 32; static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32;
/** /**
* The number of times to spin before blocking in untimed waits. * The number of times to spin before blocking in untimed waits.
@ -241,19 +241,11 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
this.item = item; this.item = item;
} }
static final AtomicReferenceFieldUpdater<SNode, SNode>
nextUpdater = AtomicReferenceFieldUpdater.newUpdater
(SNode.class, SNode.class, "next");
boolean casNext(SNode cmp, SNode val) { boolean casNext(SNode cmp, SNode val) {
return (cmp == next && return cmp == next &&
nextUpdater.compareAndSet(this, cmp, val)); UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
} }
static final AtomicReferenceFieldUpdater<SNode, SNode>
matchUpdater = AtomicReferenceFieldUpdater.newUpdater
(SNode.class, SNode.class, "match");
/** /**
* Tries to match node s to this node, if so, waking up thread. * Tries to match node s to this node, if so, waking up thread.
* Fulfillers call tryMatch to identify their waiters. * Fulfillers call tryMatch to identify their waiters.
@ -264,7 +256,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
*/ */
boolean tryMatch(SNode s) { boolean tryMatch(SNode s) {
if (match == null && if (match == null &&
matchUpdater.compareAndSet(this, null, s)) { UNSAFE.compareAndSwapObject(this, matchOffset, null, s)) {
Thread w = waiter; Thread w = waiter;
if (w != null) { // waiters need at most one unpark if (w != null) { // waiters need at most one unpark
waiter = null; waiter = null;
@ -279,23 +271,28 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
* Tries to cancel a wait by matching node to itself. * Tries to cancel a wait by matching node to itself.
*/ */
void tryCancel() { void tryCancel() {
matchUpdater.compareAndSet(this, null, this); UNSAFE.compareAndSwapObject(this, matchOffset, null, this);
} }
boolean isCancelled() { boolean isCancelled() {
return match == this; return match == this;
} }
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long nextOffset =
objectFieldOffset(UNSAFE, "next", SNode.class);
private static final long matchOffset =
objectFieldOffset(UNSAFE, "match", SNode.class);
} }
/** The head (top) of the stack */ /** The head (top) of the stack */
volatile SNode head; volatile SNode head;
static final AtomicReferenceFieldUpdater<TransferStack, SNode>
headUpdater = AtomicReferenceFieldUpdater.newUpdater
(TransferStack.class, SNode.class, "head");
boolean casHead(SNode h, SNode nh) { boolean casHead(SNode h, SNode nh) {
return h == head && headUpdater.compareAndSet(this, h, nh); return h == head &&
UNSAFE.compareAndSwapObject(this, headOffset, h, nh);
} }
/** /**
@ -338,7 +335,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
*/ */
SNode s = null; // constructed/reused as needed SNode s = null; // constructed/reused as needed
int mode = (e == null)? REQUEST : DATA; int mode = (e == null) ? REQUEST : DATA;
for (;;) { for (;;) {
SNode h = head; SNode h = head;
@ -356,7 +353,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
} }
if ((h = head) != null && h.next == s) if ((h = head) != null && h.next == s)
casHead(h, s.next); // help s's fulfiller casHead(h, s.next); // help s's fulfiller
return mode == REQUEST? m.item : s.item; return (mode == REQUEST) ? m.item : s.item;
} }
} else if (!isFulfilling(h.mode)) { // try to fulfill } else if (!isFulfilling(h.mode)) { // try to fulfill
if (h.isCancelled()) // already cancelled if (h.isCancelled()) // already cancelled
@ -372,7 +369,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
SNode mn = m.next; SNode mn = m.next;
if (m.tryMatch(s)) { if (m.tryMatch(s)) {
casHead(s, mn); // pop both s and m casHead(s, mn); // pop both s and m
return (mode == REQUEST)? m.item : s.item; return (mode == REQUEST) ? m.item : s.item;
} else // lost match } else // lost match
s.casNext(m, mn); // help unlink s.casNext(m, mn); // help unlink
} }
@ -423,11 +420,11 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
* and don't wait at all, so are trapped in transfer * and don't wait at all, so are trapped in transfer
* method rather than calling awaitFulfill. * method rather than calling awaitFulfill.
*/ */
long lastTime = (timed)? System.nanoTime() : 0; long lastTime = timed ? System.nanoTime() : 0;
Thread w = Thread.currentThread(); Thread w = Thread.currentThread();
SNode h = head; SNode h = head;
int spins = (shouldSpin(s)? int spins = (shouldSpin(s) ?
(timed? maxTimedSpins : maxUntimedSpins) : 0); (timed ? maxTimedSpins : maxUntimedSpins) : 0);
for (;;) { for (;;) {
if (w.isInterrupted()) if (w.isInterrupted())
s.tryCancel(); s.tryCancel();
@ -444,7 +441,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
} }
} }
if (spins > 0) if (spins > 0)
spins = shouldSpin(s)? (spins-1) : 0; spins = shouldSpin(s) ? (spins-1) : 0;
else if (s.waiter == null) else if (s.waiter == null)
s.waiter = w; // establish waiter so can park next iter s.waiter = w; // establish waiter so can park next iter
else if (!timed) else if (!timed)
@ -499,6 +496,12 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
p = n; p = n;
} }
} }
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long headOffset =
objectFieldOffset(UNSAFE, "head", TransferStack.class);
} }
/** Dual Queue */ /** Dual Queue */
@ -524,29 +527,21 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
this.isData = isData; this.isData = isData;
} }
static final AtomicReferenceFieldUpdater<QNode, QNode>
nextUpdater = AtomicReferenceFieldUpdater.newUpdater
(QNode.class, QNode.class, "next");
boolean casNext(QNode cmp, QNode val) { boolean casNext(QNode cmp, QNode val) {
return (next == cmp && return next == cmp &&
nextUpdater.compareAndSet(this, cmp, val)); UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
} }
static final AtomicReferenceFieldUpdater<QNode, Object>
itemUpdater = AtomicReferenceFieldUpdater.newUpdater
(QNode.class, Object.class, "item");
boolean casItem(Object cmp, Object val) { boolean casItem(Object cmp, Object val) {
return (item == cmp && return item == cmp &&
itemUpdater.compareAndSet(this, cmp, val)); UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
} }
/** /**
* Tries to cancel by CAS'ing ref to this as item. * Tries to cancel by CAS'ing ref to this as item.
*/ */
void tryCancel(Object cmp) { void tryCancel(Object cmp) {
itemUpdater.compareAndSet(this, cmp, this); UNSAFE.compareAndSwapObject(this, itemOffset, cmp, this);
} }
boolean isCancelled() { boolean isCancelled() {
@ -561,6 +556,13 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
boolean isOffList() { boolean isOffList() {
return next == this; return next == this;
} }
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long nextOffset =
objectFieldOffset(UNSAFE, "next", QNode.class);
private static final long itemOffset =
objectFieldOffset(UNSAFE, "item", QNode.class);
} }
/** Head of queue */ /** Head of queue */
@ -580,41 +582,30 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
tail = h; tail = h;
} }
static final AtomicReferenceFieldUpdater<TransferQueue, QNode>
headUpdater = AtomicReferenceFieldUpdater.newUpdater
(TransferQueue.class, QNode.class, "head");
/** /**
* Tries to cas nh as new head; if successful, unlink * Tries to cas nh as new head; if successful, unlink
* old head's next node to avoid garbage retention. * old head's next node to avoid garbage retention.
*/ */
void advanceHead(QNode h, QNode nh) { void advanceHead(QNode h, QNode nh) {
if (h == head && headUpdater.compareAndSet(this, h, nh)) if (h == head &&
UNSAFE.compareAndSwapObject(this, headOffset, h, nh))
h.next = h; // forget old next h.next = h; // forget old next
} }
static final AtomicReferenceFieldUpdater<TransferQueue, QNode>
tailUpdater = AtomicReferenceFieldUpdater.newUpdater
(TransferQueue.class, QNode.class, "tail");
/** /**
* Tries to cas nt as new tail. * Tries to cas nt as new tail.
*/ */
void advanceTail(QNode t, QNode nt) { void advanceTail(QNode t, QNode nt) {
if (tail == t) if (tail == t)
tailUpdater.compareAndSet(this, t, nt); UNSAFE.compareAndSwapObject(this, tailOffset, t, nt);
} }
static final AtomicReferenceFieldUpdater<TransferQueue, QNode>
cleanMeUpdater = AtomicReferenceFieldUpdater.newUpdater
(TransferQueue.class, QNode.class, "cleanMe");
/** /**
* Tries to CAS cleanMe slot. * Tries to CAS cleanMe slot.
*/ */
boolean casCleanMe(QNode cmp, QNode val) { boolean casCleanMe(QNode cmp, QNode val) {
return (cleanMe == cmp && return cleanMe == cmp &&
cleanMeUpdater.compareAndSet(this, cmp, val)); UNSAFE.compareAndSwapObject(this, cleanMeOffset, cmp, val);
} }
/** /**
@ -683,7 +674,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
s.item = s; s.item = s;
s.waiter = null; s.waiter = null;
} }
return (x != null)? x : e; return (x != null) ? x : e;
} else { // complementary-mode } else { // complementary-mode
QNode m = h.next; // node to fulfill QNode m = h.next; // node to fulfill
@ -700,7 +691,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
advanceHead(h, m); // successfully fulfilled advanceHead(h, m); // successfully fulfilled
LockSupport.unpark(m.waiter); LockSupport.unpark(m.waiter);
return (x != null)? x : e; return (x != null) ? x : e;
} }
} }
} }
@ -716,10 +707,10 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
*/ */
Object awaitFulfill(QNode s, Object e, boolean timed, long nanos) { Object awaitFulfill(QNode s, Object e, boolean timed, long nanos) {
/* Same idea as TransferStack.awaitFulfill */ /* Same idea as TransferStack.awaitFulfill */
long lastTime = (timed)? System.nanoTime() : 0; long lastTime = timed ? System.nanoTime() : 0;
Thread w = Thread.currentThread(); Thread w = Thread.currentThread();
int spins = ((head.next == s) ? int spins = ((head.next == s) ?
(timed? maxTimedSpins : maxUntimedSpins) : 0); (timed ? maxTimedSpins : maxUntimedSpins) : 0);
for (;;) { for (;;) {
if (w.isInterrupted()) if (w.isInterrupted())
s.tryCancel(e); s.tryCancel(e);
@ -799,6 +790,16 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
return; // Postpone cleaning s return; // Postpone cleaning s
} }
} }
// unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long headOffset =
objectFieldOffset(UNSAFE, "head", TransferQueue.class);
private static final long tailOffset =
objectFieldOffset(UNSAFE, "tail", TransferQueue.class);
private static final long cleanMeOffset =
objectFieldOffset(UNSAFE, "cleanMe", TransferQueue.class);
} }
/** /**
@ -824,7 +825,7 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
* access; otherwise the order is unspecified. * access; otherwise the order is unspecified.
*/ */
public SynchronousQueue(boolean fair) { public SynchronousQueue(boolean fair) {
transferer = (fair)? new TransferQueue() : new TransferStack(); transferer = fair ? new TransferQueue() : new TransferStack();
} }
/** /**
@ -1141,4 +1142,17 @@ public class SynchronousQueue<E> extends AbstractQueue<E>
transferer = new TransferStack(); transferer = new TransferStack();
} }
// Unsafe mechanics
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
String field, Class<?> klazz) {
try {
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
} catch (NoSuchFieldException e) {
// Convert Exception to corresponding Error
NoSuchFieldError error = new NoSuchFieldError(field);
error.initCause(e);
throw error;
}
}
} }

View File

@ -1841,6 +1841,43 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
} }
} }
/**
* Returns a string identifying this pool, as well as its state,
* including indications of run state and estimated worker and
* task counts.
*
* @return a string identifying this pool, as well as its state
*/
public String toString() {
long ncompleted;
int nworkers, nactive;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
ncompleted = completedTaskCount;
nactive = 0;
nworkers = workers.size();
for (Worker w : workers) {
ncompleted += w.completedTasks;
if (w.isLocked())
++nactive;
}
} finally {
mainLock.unlock();
}
int c = ctl.get();
String rs = (runStateLessThan(c, SHUTDOWN) ? "Running" :
(runStateAtLeast(c, TERMINATED) ? "Terminated" :
"Shutting down"));
return super.toString() +
"[" + rs +
", pool size = " + nworkers +
", active threads = " + nactive +
", queued tasks = " + workQueue.size() +
", completed tasks = " + ncompleted +
"]";
}
/* Extension hooks */ /* Extension hooks */
/** /**
@ -1961,7 +1998,9 @@ public class ThreadPoolExecutor extends AbstractExecutorService {
* @throws RejectedExecutionException always. * @throws RejectedExecutionException always.
*/ */
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException(); throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
} }
} }

View File

@ -48,28 +48,37 @@ import java.util.*;
public class AtomicIntegerArray implements java.io.Serializable { public class AtomicIntegerArray implements java.io.Serializable {
private static final long serialVersionUID = 2862133569453604235L; private static final long serialVersionUID = 2862133569453604235L;
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final int base = unsafe.arrayBaseOffset(int[].class); private static final int base = unsafe.arrayBaseOffset(int[].class);
private static final int scale = unsafe.arrayIndexScale(int[].class); private static final int shift;
private final int[] array; private final int[] array;
private long rawIndex(int i) { static {
int scale = unsafe.arrayIndexScale(int[].class);
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
shift = 31 - Integer.numberOfLeadingZeros(scale);
}
private long checkedByteOffset(int i) {
if (i < 0 || i >= array.length) if (i < 0 || i >= array.length)
throw new IndexOutOfBoundsException("index " + i); throw new IndexOutOfBoundsException("index " + i);
return base + (long) i * scale;
return byteOffset(i);
}
private static long byteOffset(int i) {
return ((long) i << shift) + base;
} }
/** /**
* Creates a new AtomicIntegerArray of given length. * Creates a new AtomicIntegerArray of the given length, with all
* elements initially zero.
* *
* @param length the length of the array * @param length the length of the array
*/ */
public AtomicIntegerArray(int length) { public AtomicIntegerArray(int length) {
array = new int[length]; array = new int[length];
// must perform at least one volatile write to conform to JMM
if (length > 0)
unsafe.putIntVolatile(array, rawIndex(0), 0);
} }
/** /**
@ -80,17 +89,8 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @throws NullPointerException if array is null * @throws NullPointerException if array is null
*/ */
public AtomicIntegerArray(int[] array) { public AtomicIntegerArray(int[] array) {
if (array == null) // Visibility guaranteed by final field guarantees
throw new NullPointerException(); this.array = array.clone();
int length = array.length;
this.array = new int[length];
if (length > 0) {
int last = length-1;
for (int i = 0; i < last; ++i)
this.array[i] = array[i];
// Do the last write as volatile
unsafe.putIntVolatile(this.array, rawIndex(last), array[last]);
}
} }
/** /**
@ -109,7 +109,11 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @return the current value * @return the current value
*/ */
public final int get(int i) { public final int get(int i) {
return unsafe.getIntVolatile(array, rawIndex(i)); return getRaw(checkedByteOffset(i));
}
private int getRaw(long offset) {
return unsafe.getIntVolatile(array, offset);
} }
/** /**
@ -119,7 +123,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @param newValue the new value * @param newValue the new value
*/ */
public final void set(int i, int newValue) { public final void set(int i, int newValue) {
unsafe.putIntVolatile(array, rawIndex(i), newValue); unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
} }
/** /**
@ -130,7 +134,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @since 1.6 * @since 1.6
*/ */
public final void lazySet(int i, int newValue) { public final void lazySet(int i, int newValue) {
unsafe.putOrderedInt(array, rawIndex(i), newValue); unsafe.putOrderedInt(array, checkedByteOffset(i), newValue);
} }
/** /**
@ -142,9 +146,10 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @return the previous value * @return the previous value
*/ */
public final int getAndSet(int i, int newValue) { public final int getAndSet(int i, int newValue) {
long offset = checkedByteOffset(i);
while (true) { while (true) {
int current = get(i); int current = getRaw(offset);
if (compareAndSet(i, current, newValue)) if (compareAndSetRaw(offset, current, newValue))
return current; return current;
} }
} }
@ -160,8 +165,11 @@ public class AtomicIntegerArray implements java.io.Serializable {
* the actual value was not equal to the expected value. * the actual value was not equal to the expected value.
*/ */
public final boolean compareAndSet(int i, int expect, int update) { public final boolean compareAndSet(int i, int expect, int update) {
return unsafe.compareAndSwapInt(array, rawIndex(i), return compareAndSetRaw(checkedByteOffset(i), expect, update);
expect, update); }
private boolean compareAndSetRaw(long offset, int expect, int update) {
return unsafe.compareAndSwapInt(array, offset, expect, update);
} }
/** /**
@ -188,12 +196,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @return the previous value * @return the previous value
*/ */
public final int getAndIncrement(int i) { public final int getAndIncrement(int i) {
while (true) { return getAndAdd(i, 1);
int current = get(i);
int next = current + 1;
if (compareAndSet(i, current, next))
return current;
}
} }
/** /**
@ -203,12 +206,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @return the previous value * @return the previous value
*/ */
public final int getAndDecrement(int i) { public final int getAndDecrement(int i) {
while (true) { return getAndAdd(i, -1);
int current = get(i);
int next = current - 1;
if (compareAndSet(i, current, next))
return current;
}
} }
/** /**
@ -219,10 +217,10 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @return the previous value * @return the previous value
*/ */
public final int getAndAdd(int i, int delta) { public final int getAndAdd(int i, int delta) {
long offset = checkedByteOffset(i);
while (true) { while (true) {
int current = get(i); int current = getRaw(offset);
int next = current + delta; if (compareAndSetRaw(offset, current, current + delta))
if (compareAndSet(i, current, next))
return current; return current;
} }
} }
@ -234,12 +232,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @return the updated value * @return the updated value
*/ */
public final int incrementAndGet(int i) { public final int incrementAndGet(int i) {
while (true) { return addAndGet(i, 1);
int current = get(i);
int next = current + 1;
if (compareAndSet(i, current, next))
return next;
}
} }
/** /**
@ -249,12 +242,7 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @return the updated value * @return the updated value
*/ */
public final int decrementAndGet(int i) { public final int decrementAndGet(int i) {
while (true) { return addAndGet(i, -1);
int current = get(i);
int next = current - 1;
if (compareAndSet(i, current, next))
return next;
}
} }
/** /**
@ -265,22 +253,32 @@ public class AtomicIntegerArray implements java.io.Serializable {
* @return the updated value * @return the updated value
*/ */
public final int addAndGet(int i, int delta) { public final int addAndGet(int i, int delta) {
long offset = checkedByteOffset(i);
while (true) { while (true) {
int current = get(i); int current = getRaw(offset);
int next = current + delta; int next = current + delta;
if (compareAndSet(i, current, next)) if (compareAndSetRaw(offset, current, next))
return next; return next;
} }
} }
/** /**
* Returns the String representation of the current values of array. * Returns the String representation of the current values of array.
* @return the String representation of the current values of array. * @return the String representation of the current values of array
*/ */
public String toString() { public String toString() {
if (array.length > 0) // force volatile read int iMax = array.length - 1;
get(0); if (iMax == -1)
return Arrays.toString(array); return "[]";
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(getRaw(byteOffset(i)));
if (i == iMax)
return b.append(']').toString();
b.append(',').append(' ');
}
} }
} }

View File

@ -47,28 +47,37 @@ import java.util.*;
public class AtomicLongArray implements java.io.Serializable { public class AtomicLongArray implements java.io.Serializable {
private static final long serialVersionUID = -2308431214976778248L; private static final long serialVersionUID = -2308431214976778248L;
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final int base = unsafe.arrayBaseOffset(long[].class); private static final int base = unsafe.arrayBaseOffset(long[].class);
private static final int scale = unsafe.arrayIndexScale(long[].class); private static final int shift;
private final long[] array; private final long[] array;
private long rawIndex(int i) { static {
int scale = unsafe.arrayIndexScale(long[].class);
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
shift = 31 - Integer.numberOfLeadingZeros(scale);
}
private long checkedByteOffset(int i) {
if (i < 0 || i >= array.length) if (i < 0 || i >= array.length)
throw new IndexOutOfBoundsException("index " + i); throw new IndexOutOfBoundsException("index " + i);
return base + (long) i * scale;
return byteOffset(i);
}
private static long byteOffset(int i) {
return ((long) i << shift) + base;
} }
/** /**
* Creates a new AtomicLongArray of given length. * Creates a new AtomicLongArray of the given length, with all
* elements initially zero.
* *
* @param length the length of the array * @param length the length of the array
*/ */
public AtomicLongArray(int length) { public AtomicLongArray(int length) {
array = new long[length]; array = new long[length];
// must perform at least one volatile write to conform to JMM
if (length > 0)
unsafe.putLongVolatile(array, rawIndex(0), 0);
} }
/** /**
@ -79,17 +88,8 @@ public class AtomicLongArray implements java.io.Serializable {
* @throws NullPointerException if array is null * @throws NullPointerException if array is null
*/ */
public AtomicLongArray(long[] array) { public AtomicLongArray(long[] array) {
if (array == null) // Visibility guaranteed by final field guarantees
throw new NullPointerException(); this.array = array.clone();
int length = array.length;
this.array = new long[length];
if (length > 0) {
int last = length-1;
for (int i = 0; i < last; ++i)
this.array[i] = array[i];
// Do the last write as volatile
unsafe.putLongVolatile(this.array, rawIndex(last), array[last]);
}
} }
/** /**
@ -108,7 +108,11 @@ public class AtomicLongArray implements java.io.Serializable {
* @return the current value * @return the current value
*/ */
public final long get(int i) { public final long get(int i) {
return unsafe.getLongVolatile(array, rawIndex(i)); return getRaw(checkedByteOffset(i));
}
private long getRaw(long offset) {
return unsafe.getLongVolatile(array, offset);
} }
/** /**
@ -118,7 +122,7 @@ public class AtomicLongArray implements java.io.Serializable {
* @param newValue the new value * @param newValue the new value
*/ */
public final void set(int i, long newValue) { public final void set(int i, long newValue) {
unsafe.putLongVolatile(array, rawIndex(i), newValue); unsafe.putLongVolatile(array, checkedByteOffset(i), newValue);
} }
/** /**
@ -129,7 +133,7 @@ public class AtomicLongArray implements java.io.Serializable {
* @since 1.6 * @since 1.6
*/ */
public final void lazySet(int i, long newValue) { public final void lazySet(int i, long newValue) {
unsafe.putOrderedLong(array, rawIndex(i), newValue); unsafe.putOrderedLong(array, checkedByteOffset(i), newValue);
} }
@ -142,16 +146,17 @@ public class AtomicLongArray implements java.io.Serializable {
* @return the previous value * @return the previous value
*/ */
public final long getAndSet(int i, long newValue) { public final long getAndSet(int i, long newValue) {
long offset = checkedByteOffset(i);
while (true) { while (true) {
long current = get(i); long current = getRaw(offset);
if (compareAndSet(i, current, newValue)) if (compareAndSetRaw(offset, current, newValue))
return current; return current;
} }
} }
/** /**
* Atomically sets the value to the given updated value * Atomically sets the element at position {@code i} to the given
* if the current value {@code ==} the expected value. * updated value if the current value {@code ==} the expected value.
* *
* @param i the index * @param i the index
* @param expect the expected value * @param expect the expected value
@ -160,13 +165,16 @@ public class AtomicLongArray implements java.io.Serializable {
* the actual value was not equal to the expected value. * the actual value was not equal to the expected value.
*/ */
public final boolean compareAndSet(int i, long expect, long update) { public final boolean compareAndSet(int i, long expect, long update) {
return unsafe.compareAndSwapLong(array, rawIndex(i), return compareAndSetRaw(checkedByteOffset(i), expect, update);
expect, update); }
private boolean compareAndSetRaw(long offset, long expect, long update) {
return unsafe.compareAndSwapLong(array, offset, expect, update);
} }
/** /**
* Atomically sets the value to the given updated value * Atomically sets the element at position {@code i} to the given
* if the current value {@code ==} the expected value. * updated value if the current value {@code ==} the expected value.
* *
* <p>May <a href="package-summary.html#Spurious">fail spuriously</a> * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
* and does not provide ordering guarantees, so is only rarely an * and does not provide ordering guarantees, so is only rarely an
@ -188,12 +196,7 @@ public class AtomicLongArray implements java.io.Serializable {
* @return the previous value * @return the previous value
*/ */
public final long getAndIncrement(int i) { public final long getAndIncrement(int i) {
while (true) { return getAndAdd(i, 1);
long current = get(i);
long next = current + 1;
if (compareAndSet(i, current, next))
return current;
}
} }
/** /**
@ -203,12 +206,7 @@ public class AtomicLongArray implements java.io.Serializable {
* @return the previous value * @return the previous value
*/ */
public final long getAndDecrement(int i) { public final long getAndDecrement(int i) {
while (true) { return getAndAdd(i, -1);
long current = get(i);
long next = current - 1;
if (compareAndSet(i, current, next))
return current;
}
} }
/** /**
@ -219,10 +217,10 @@ public class AtomicLongArray implements java.io.Serializable {
* @return the previous value * @return the previous value
*/ */
public final long getAndAdd(int i, long delta) { public final long getAndAdd(int i, long delta) {
long offset = checkedByteOffset(i);
while (true) { while (true) {
long current = get(i); long current = getRaw(offset);
long next = current + delta; if (compareAndSetRaw(offset, current, current + delta))
if (compareAndSet(i, current, next))
return current; return current;
} }
} }
@ -234,12 +232,7 @@ public class AtomicLongArray implements java.io.Serializable {
* @return the updated value * @return the updated value
*/ */
public final long incrementAndGet(int i) { public final long incrementAndGet(int i) {
while (true) { return addAndGet(i, 1);
long current = get(i);
long next = current + 1;
if (compareAndSet(i, current, next))
return next;
}
} }
/** /**
@ -249,12 +242,7 @@ public class AtomicLongArray implements java.io.Serializable {
* @return the updated value * @return the updated value
*/ */
public final long decrementAndGet(int i) { public final long decrementAndGet(int i) {
while (true) { return addAndGet(i, -1);
long current = get(i);
long next = current - 1;
if (compareAndSet(i, current, next))
return next;
}
} }
/** /**
@ -265,22 +253,32 @@ public class AtomicLongArray implements java.io.Serializable {
* @return the updated value * @return the updated value
*/ */
public long addAndGet(int i, long delta) { public long addAndGet(int i, long delta) {
long offset = checkedByteOffset(i);
while (true) { while (true) {
long current = get(i); long current = getRaw(offset);
long next = current + delta; long next = current + delta;
if (compareAndSet(i, current, next)) if (compareAndSetRaw(offset, current, next))
return next; return next;
} }
} }
/** /**
* Returns the String representation of the current values of array. * Returns the String representation of the current values of array.
* @return the String representation of the current values of array. * @return the String representation of the current values of array
*/ */
public String toString() { public String toString() {
if (array.length > 0) // force volatile read int iMax = array.length - 1;
get(0); if (iMax == -1)
return Arrays.toString(array); return "[]";
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(getRaw(byteOffset(i)));
if (i == iMax)
return b.append(']').toString();
b.append(',').append(' ');
}
} }
} }

View File

@ -38,8 +38,8 @@ package java.util.concurrent.atomic;
/** /**
* An {@code AtomicMarkableReference} maintains an object reference * An {@code AtomicMarkableReference} maintains an object reference
* along with a mark bit, that can be updated atomically. * along with a mark bit, that can be updated atomically.
* <p> *
* <p> Implementation note. This implementation maintains markable * <p>Implementation note: This implementation maintains markable
* references by creating internal objects representing "boxed" * references by creating internal objects representing "boxed"
* [reference, boolean] pairs. * [reference, boolean] pairs.
* *
@ -47,17 +47,21 @@ package java.util.concurrent.atomic;
* @author Doug Lea * @author Doug Lea
* @param <V> The type of object referred to by this reference * @param <V> The type of object referred to by this reference
*/ */
public class AtomicMarkableReference<V> { public class AtomicMarkableReference<V> {
private static class ReferenceBooleanPair<T> { private static class Pair<T> {
private final T reference; final T reference;
private final boolean bit; final boolean mark;
ReferenceBooleanPair(T r, boolean i) { private Pair(T reference, boolean mark) {
reference = r; bit = i; this.reference = reference;
this.mark = mark;
}
static <T> Pair<T> of(T reference, boolean mark) {
return new Pair<T>(reference, mark);
} }
} }
private final AtomicReference<ReferenceBooleanPair<V>> atomicRef; private volatile Pair<V> pair;
/** /**
* Creates a new {@code AtomicMarkableReference} with the given * Creates a new {@code AtomicMarkableReference} with the given
@ -67,7 +71,7 @@ public class AtomicMarkableReference<V> {
* @param initialMark the initial mark * @param initialMark the initial mark
*/ */
public AtomicMarkableReference(V initialRef, boolean initialMark) { public AtomicMarkableReference(V initialRef, boolean initialMark) {
atomicRef = new AtomicReference<ReferenceBooleanPair<V>> (new ReferenceBooleanPair<V>(initialRef, initialMark)); pair = Pair.of(initialRef, initialMark);
} }
/** /**
@ -76,7 +80,7 @@ public class AtomicMarkableReference<V> {
* @return the current value of the reference * @return the current value of the reference
*/ */
public V getReference() { public V getReference() {
return atomicRef.get().reference; return pair.reference;
} }
/** /**
@ -85,7 +89,7 @@ public class AtomicMarkableReference<V> {
* @return the current value of the mark * @return the current value of the mark
*/ */
public boolean isMarked() { public boolean isMarked() {
return atomicRef.get().bit; return pair.mark;
} }
/** /**
@ -97,9 +101,9 @@ public class AtomicMarkableReference<V> {
* @return the current value of the reference * @return the current value of the reference
*/ */
public V get(boolean[] markHolder) { public V get(boolean[] markHolder) {
ReferenceBooleanPair<V> p = atomicRef.get(); Pair<V> pair = this.pair;
markHolder[0] = p.bit; markHolder[0] = pair.mark;
return p.reference; return pair.reference;
} }
/** /**
@ -122,13 +126,8 @@ public class AtomicMarkableReference<V> {
V newReference, V newReference,
boolean expectedMark, boolean expectedMark,
boolean newMark) { boolean newMark) {
ReferenceBooleanPair<V> current = atomicRef.get(); return compareAndSet(expectedReference, newReference,
return expectedReference == current.reference && expectedMark, newMark);
expectedMark == current.bit &&
((newReference == current.reference && newMark == current.bit) ||
atomicRef.weakCompareAndSet(current,
new ReferenceBooleanPair<V>(newReference,
newMark)));
} }
/** /**
@ -147,13 +146,13 @@ public class AtomicMarkableReference<V> {
V newReference, V newReference,
boolean expectedMark, boolean expectedMark,
boolean newMark) { boolean newMark) {
ReferenceBooleanPair<V> current = atomicRef.get(); Pair<V> current = pair;
return expectedReference == current.reference && return
expectedMark == current.bit && expectedReference == current.reference &&
((newReference == current.reference && newMark == current.bit) || expectedMark == current.mark &&
atomicRef.compareAndSet(current, ((newReference == current.reference &&
new ReferenceBooleanPair<V>(newReference, newMark == current.mark) ||
newMark))); casPair(current, Pair.of(newReference, newMark)));
} }
/** /**
@ -163,9 +162,9 @@ public class AtomicMarkableReference<V> {
* @param newMark the new value for the mark * @param newMark the new value for the mark
*/ */
public void set(V newReference, boolean newMark) { public void set(V newReference, boolean newMark) {
ReferenceBooleanPair<V> current = atomicRef.get(); Pair<V> current = pair;
if (newReference != current.reference || newMark != current.bit) if (newReference != current.reference || newMark != current.mark)
atomicRef.set(new ReferenceBooleanPair<V>(newReference, newMark)); this.pair = Pair.of(newReference, newMark);
} }
/** /**
@ -182,11 +181,32 @@ public class AtomicMarkableReference<V> {
* @return true if successful * @return true if successful
*/ */
public boolean attemptMark(V expectedReference, boolean newMark) { public boolean attemptMark(V expectedReference, boolean newMark) {
ReferenceBooleanPair<V> current = atomicRef.get(); Pair<V> current = pair;
return expectedReference == current.reference && return
(newMark == current.bit || expectedReference == current.reference &&
atomicRef.compareAndSet (newMark == current.mark ||
(current, new ReferenceBooleanPair<V>(expectedReference, casPair(current, Pair.of(expectedReference, newMark)));
newMark))); }
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long pairOffset =
objectFieldOffset(UNSAFE, "pair", AtomicMarkableReference.class);
private boolean casPair(Pair<V> cmp, Pair<V> val) {
return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
}
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
String field, Class<?> klazz) {
try {
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
} catch (NoSuchFieldException e) {
// Convert Exception to corresponding Error
NoSuchFieldError error = new NoSuchFieldError(field);
error.initCause(e);
throw error;
}
} }
} }

View File

@ -51,24 +51,35 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final int base = unsafe.arrayBaseOffset(Object[].class); private static final int base = unsafe.arrayBaseOffset(Object[].class);
private static final int scale = unsafe.arrayIndexScale(Object[].class); private static final int shift;
private final Object[] array; private final Object[] array;
private long rawIndex(int i) { static {
int scale = unsafe.arrayIndexScale(Object[].class);
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
shift = 31 - Integer.numberOfLeadingZeros(scale);
}
private long checkedByteOffset(int i) {
if (i < 0 || i >= array.length) if (i < 0 || i >= array.length)
throw new IndexOutOfBoundsException("index " + i); throw new IndexOutOfBoundsException("index " + i);
return base + (long) i * scale;
return byteOffset(i);
}
private static long byteOffset(int i) {
return ((long) i << shift) + base;
} }
/** /**
* Creates a new AtomicReferenceArray of given length. * Creates a new AtomicReferenceArray of the given length, with all
* elements initially null.
*
* @param length the length of the array * @param length the length of the array
*/ */
public AtomicReferenceArray(int length) { public AtomicReferenceArray(int length) {
array = new Object[length]; array = new Object[length];
// must perform at least one volatile write to conform to JMM
if (length > 0)
unsafe.putObjectVolatile(array, rawIndex(0), null);
} }
/** /**
@ -79,18 +90,8 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
* @throws NullPointerException if array is null * @throws NullPointerException if array is null
*/ */
public AtomicReferenceArray(E[] array) { public AtomicReferenceArray(E[] array) {
if (array == null) // Visibility guaranteed by final field guarantees
throw new NullPointerException(); this.array = array.clone();
int length = array.length;
this.array = new Object[length];
if (length > 0) {
int last = length-1;
for (int i = 0; i < last; ++i)
this.array[i] = array[i];
// Do the last write as volatile
E e = array[last];
unsafe.putObjectVolatile(this.array, rawIndex(last), e);
}
} }
/** /**
@ -109,7 +110,11 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
* @return the current value * @return the current value
*/ */
public final E get(int i) { public final E get(int i) {
return (E) unsafe.getObjectVolatile(array, rawIndex(i)); return getRaw(checkedByteOffset(i));
}
private E getRaw(long offset) {
return (E) unsafe.getObjectVolatile(array, offset);
} }
/** /**
@ -119,7 +124,7 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
* @param newValue the new value * @param newValue the new value
*/ */
public final void set(int i, E newValue) { public final void set(int i, E newValue) {
unsafe.putObjectVolatile(array, rawIndex(i), newValue); unsafe.putObjectVolatile(array, checkedByteOffset(i), newValue);
} }
/** /**
@ -130,7 +135,7 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
* @since 1.6 * @since 1.6
*/ */
public final void lazySet(int i, E newValue) { public final void lazySet(int i, E newValue) {
unsafe.putOrderedObject(array, rawIndex(i), newValue); unsafe.putOrderedObject(array, checkedByteOffset(i), newValue);
} }
@ -143,9 +148,10 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
* @return the previous value * @return the previous value
*/ */
public final E getAndSet(int i, E newValue) { public final E getAndSet(int i, E newValue) {
long offset = checkedByteOffset(i);
while (true) { while (true) {
E current = get(i); E current = (E) getRaw(offset);
if (compareAndSet(i, current, newValue)) if (compareAndSetRaw(offset, current, newValue))
return current; return current;
} }
} }
@ -153,6 +159,7 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
/** /**
* Atomically sets the element at position {@code i} to the given * Atomically sets the element at position {@code i} to the given
* updated value if the current value {@code ==} the expected value. * updated value if the current value {@code ==} the expected value.
*
* @param i the index * @param i the index
* @param expect the expected value * @param expect the expected value
* @param update the new value * @param update the new value
@ -160,8 +167,11 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
* the actual value was not equal to the expected value. * the actual value was not equal to the expected value.
*/ */
public final boolean compareAndSet(int i, E expect, E update) { public final boolean compareAndSet(int i, E expect, E update) {
return unsafe.compareAndSwapObject(array, rawIndex(i), return compareAndSetRaw(checkedByteOffset(i), expect, update);
expect, update); }
private boolean compareAndSetRaw(long offset, E expect, E update) {
return unsafe.compareAndSwapObject(array, offset, expect, update);
} }
/** /**
@ -183,12 +193,21 @@ public class AtomicReferenceArray<E> implements java.io.Serializable {
/** /**
* Returns the String representation of the current values of array. * Returns the String representation of the current values of array.
* @return the String representation of the current values of array. * @return the String representation of the current values of array
*/ */
public String toString() { public String toString() {
if (array.length > 0) // force volatile read int iMax = array.length - 1;
get(0); if (iMax == -1)
return Arrays.toString(array); return "[]";
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(getRaw(byteOffset(i)));
if (i == iMax)
return b.append(']').toString();
b.append(',').append(' ');
}
} }
} }

View File

@ -39,7 +39,7 @@ package java.util.concurrent.atomic;
* An {@code AtomicStampedReference} maintains an object reference * An {@code AtomicStampedReference} maintains an object reference
* along with an integer "stamp", that can be updated atomically. * along with an integer "stamp", that can be updated atomically.
* *
* <p> Implementation note. This implementation maintains stamped * <p>Implementation note: This implementation maintains stamped
* references by creating internal objects representing "boxed" * references by creating internal objects representing "boxed"
* [reference, integer] pairs. * [reference, integer] pairs.
* *
@ -47,17 +47,21 @@ package java.util.concurrent.atomic;
* @author Doug Lea * @author Doug Lea
* @param <V> The type of object referred to by this reference * @param <V> The type of object referred to by this reference
*/ */
public class AtomicStampedReference<V> { public class AtomicStampedReference<V> {
private static class ReferenceIntegerPair<T> { private static class Pair<T> {
private final T reference; final T reference;
private final int integer; final int stamp;
ReferenceIntegerPair(T r, int i) { private Pair(T reference, int stamp) {
reference = r; integer = i; this.reference = reference;
this.stamp = stamp;
}
static <T> Pair<T> of(T reference, int stamp) {
return new Pair<T>(reference, stamp);
} }
} }
private final AtomicReference<ReferenceIntegerPair<V>> atomicRef; private volatile Pair<V> pair;
/** /**
* Creates a new {@code AtomicStampedReference} with the given * Creates a new {@code AtomicStampedReference} with the given
@ -67,8 +71,7 @@ public class AtomicStampedReference<V> {
* @param initialStamp the initial stamp * @param initialStamp the initial stamp
*/ */
public AtomicStampedReference(V initialRef, int initialStamp) { public AtomicStampedReference(V initialRef, int initialStamp) {
atomicRef = new AtomicReference<ReferenceIntegerPair<V>> pair = Pair.of(initialRef, initialStamp);
(new ReferenceIntegerPair<V>(initialRef, initialStamp));
} }
/** /**
@ -77,7 +80,7 @@ public class AtomicStampedReference<V> {
* @return the current value of the reference * @return the current value of the reference
*/ */
public V getReference() { public V getReference() {
return atomicRef.get().reference; return pair.reference;
} }
/** /**
@ -86,7 +89,7 @@ public class AtomicStampedReference<V> {
* @return the current value of the stamp * @return the current value of the stamp
*/ */
public int getStamp() { public int getStamp() {
return atomicRef.get().integer; return pair.stamp;
} }
/** /**
@ -98,9 +101,9 @@ public class AtomicStampedReference<V> {
* @return the current value of the reference * @return the current value of the reference
*/ */
public V get(int[] stampHolder) { public V get(int[] stampHolder) {
ReferenceIntegerPair<V> p = atomicRef.get(); Pair<V> pair = this.pair;
stampHolder[0] = p.integer; stampHolder[0] = pair.stamp;
return p.reference; return pair.reference;
} }
/** /**
@ -119,18 +122,12 @@ public class AtomicStampedReference<V> {
* @param newStamp the new value for the stamp * @param newStamp the new value for the stamp
* @return true if successful * @return true if successful
*/ */
public boolean weakCompareAndSet(V expectedReference, public boolean weakCompareAndSet(V expectedReference,
V newReference, V newReference,
int expectedStamp, int expectedStamp,
int newStamp) { int newStamp) {
ReferenceIntegerPair<V> current = atomicRef.get(); return compareAndSet(expectedReference, newReference,
return expectedReference == current.reference && expectedStamp, newStamp);
expectedStamp == current.integer &&
((newReference == current.reference &&
newStamp == current.integer) ||
atomicRef.weakCompareAndSet(current,
new ReferenceIntegerPair<V>(newReference,
newStamp)));
} }
/** /**
@ -145,18 +142,17 @@ public class AtomicStampedReference<V> {
* @param newStamp the new value for the stamp * @param newStamp the new value for the stamp
* @return true if successful * @return true if successful
*/ */
public boolean compareAndSet(V expectedReference, public boolean compareAndSet(V expectedReference,
V newReference, V newReference,
int expectedStamp, int expectedStamp,
int newStamp) { int newStamp) {
ReferenceIntegerPair<V> current = atomicRef.get(); Pair<V> current = pair;
return expectedReference == current.reference && return
expectedStamp == current.integer && expectedReference == current.reference &&
expectedStamp == current.stamp &&
((newReference == current.reference && ((newReference == current.reference &&
newStamp == current.integer) || newStamp == current.stamp) ||
atomicRef.compareAndSet(current, casPair(current, Pair.of(newReference, newStamp)));
new ReferenceIntegerPair<V>(newReference,
newStamp)));
} }
@ -167,9 +163,9 @@ public class AtomicStampedReference<V> {
* @param newStamp the new value for the stamp * @param newStamp the new value for the stamp
*/ */
public void set(V newReference, int newStamp) { public void set(V newReference, int newStamp) {
ReferenceIntegerPair<V> current = atomicRef.get(); Pair<V> current = pair;
if (newReference != current.reference || newStamp != current.integer) if (newReference != current.reference || newStamp != current.stamp)
atomicRef.set(new ReferenceIntegerPair<V>(newReference, newStamp)); this.pair = Pair.of(newReference, newStamp);
} }
/** /**
@ -186,11 +182,32 @@ public class AtomicStampedReference<V> {
* @return true if successful * @return true if successful
*/ */
public boolean attemptStamp(V expectedReference, int newStamp) { public boolean attemptStamp(V expectedReference, int newStamp) {
ReferenceIntegerPair<V> current = atomicRef.get(); Pair<V> current = pair;
return expectedReference == current.reference && return
(newStamp == current.integer || expectedReference == current.reference &&
atomicRef.compareAndSet(current, (newStamp == current.stamp ||
new ReferenceIntegerPair<V>(expectedReference, casPair(current, Pair.of(expectedReference, newStamp)));
newStamp))); }
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long pairOffset =
objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class);
private boolean casPair(Pair<V> cmp, Pair<V> val) {
return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
}
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
String field, Class<?> klazz) {
try {
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
} catch (NoSuchFieldException e) {
// Convert Exception to corresponding Error
NoSuchFieldError error = new NoSuchFieldError(field);
error.initCause(e);
throw error;
}
} }
} }

View File

@ -308,18 +308,21 @@ public interface Condition {
* condition still does not hold. Typical uses of this method take * condition still does not hold. Typical uses of this method take
* the following form: * the following form:
* *
* <pre> * <pre> {@code
* synchronized boolean aMethod(long timeout, TimeUnit unit) { * boolean aMethod(long timeout, TimeUnit unit) {
* long nanosTimeout = unit.toNanos(timeout); * long nanos = unit.toNanos(timeout);
* while (!conditionBeingWaitedFor) { * lock.lock();
* if (nanosTimeout &gt; 0) * try {
* nanosTimeout = theCondition.awaitNanos(nanosTimeout); * while (!conditionBeingWaitedFor()) {
* else * if (nanos <= 0L)
* return false; * return false;
* nanos = theCondition.awaitNanos(nanos);
* }
* // ...
* } finally {
* lock.unlock();
* } * }
* // ... * }}</pre>
* }
* </pre>
* *
* <p> Design note: This method requires a nanosecond argument so * <p> Design note: This method requires a nanosecond argument so
* as to avoid truncation errors in reporting remaining times. * as to avoid truncation errors in reporting remaining times.
@ -408,18 +411,21 @@ public interface Condition {
* *
* <p>The return value indicates whether the deadline has elapsed, * <p>The return value indicates whether the deadline has elapsed,
* which can be used as follows: * which can be used as follows:
* <pre> * <pre> {@code
* synchronized boolean aMethod(Date deadline) { * boolean aMethod(Date deadline) {
* boolean stillWaiting = true; * boolean stillWaiting = true;
* while (!conditionBeingWaitedFor) { * lock.lock();
* if (stillWaiting) * try {
* stillWaiting = theCondition.awaitUntil(deadline); * while (!conditionBeingWaitedFor()) {
* else * if (!stillWaiting)
* return false; * return false;
* stillWaiting = theCondition.awaitUntil(deadline);
* }
* // ...
* } finally {
* lock.unlock();
* } * }
* // ... * }}</pre>
* }
* </pre>
* *
* <p><b>Implementation Considerations</b> * <p><b>Implementation Considerations</b>
* *
@ -450,6 +456,15 @@ public interface Condition {
* <p>If any threads are waiting on this condition then one * <p>If any threads are waiting on this condition then one
* is selected for waking up. That thread must then re-acquire the * is selected for waking up. That thread must then re-acquire the
* lock before returning from {@code await}. * lock before returning from {@code await}.
*
* <p><b>Implementation Considerations</b>
*
* <p>An implementation may (and typically does) require that the
* current thread hold the lock associated with this {@code
* Condition} when this method is called. Implementations must
* document this precondition and any actions taken if the lock is
* not held. Typically, an exception such as {@link
* IllegalMonitorStateException} will be thrown.
*/ */
void signal(); void signal();
@ -459,6 +474,15 @@ public interface Condition {
* <p>If any threads are waiting on this condition then they are * <p>If any threads are waiting on this condition then they are
* all woken up. Each thread must re-acquire the lock before it can * all woken up. Each thread must re-acquire the lock before it can
* return from {@code await}. * return from {@code await}.
*
* <p><b>Implementation Considerations</b>
*
* <p>An implementation may (and typically does) require that the
* current thread hold the lock associated with this {@code
* Condition} when this method is called. Implementations must
* document this precondition and any actions taken if the lock is
* not held. Typically, an exception such as {@link
* IllegalMonitorStateException} will be thrown.
*/ */
void signalAll(); void signalAll();
} }

View File

@ -1426,7 +1426,7 @@ public class Logger {
// we didn't have a previous parent // we didn't have a previous parent
ref = manager.new LoggerWeakRef(this); ref = manager.new LoggerWeakRef(this);
} }
ref.setParentRef(new WeakReference<>(parent)); ref.setParentRef(new WeakReference<Logger>(parent));
parent.kids.add(ref); parent.kids.add(ref);
// As a result of the reparenting, the effective level // As a result of the reparenting, the effective level

View File

@ -466,6 +466,7 @@ public class URLClassPath {
*/ */
private static class Loader implements Closeable { private static class Loader implements Closeable {
private final URL base; private final URL base;
private JarFile jarfile; // if this points to a jar file
/* /*
* Creates a new Loader for the specified URL. * Creates a new Loader for the specified URL.
@ -530,6 +531,17 @@ public class URLClassPath {
} }
uc = url.openConnection(); uc = url.openConnection();
InputStream in = uc.getInputStream(); InputStream in = uc.getInputStream();
if (uc instanceof JarURLConnection) {
/* JarURLConnection.getInputStream() returns a separate
* instance on each call. So we have to close this here.
* The jar file cache will keep the file open.
* Also, need to remember the jar file so it can be closed
* in a hurry.
*/
JarURLConnection juc = (JarURLConnection)uc;
jarfile = juc.getJarFile();
in.close();
}
} catch (Exception e) { } catch (Exception e) {
return null; return null;
} }
@ -559,7 +571,11 @@ public class URLClassPath {
* close this loader and release all resources * close this loader and release all resources
* method overridden in sub-classes * method overridden in sub-classes
*/ */
public void close () throws IOException {} public void close () throws IOException {
if (jarfile != null) {
jarfile.close();
}
}
/* /*
* Returns the local class path for this loader, or null if none. * Returns the local class path for this loader, or null if none.

View File

@ -528,7 +528,7 @@ public class Config {
} }
}))); })));
String Line; String Line;
Vector<String> v = new Vector<String> (); Vector<String> v = new Vector<>();
String previous = null; String previous = null;
while ((Line = br.readLine()) != null) { while ((Line = br.readLine()) != null) {
// ignore comments and blank line in the configuration file. // ignore comments and blank line in the configuration file.
@ -589,7 +589,7 @@ public class Config {
throw new KrbException("I/O error while reading" + throw new KrbException("I/O error while reading" +
" configuration file."); " configuration file.");
} }
Hashtable<String,Object> table = new Hashtable<String,Object> (); Hashtable<String,Object> table = new Hashtable<>();
for (int i = 0; i < v.size(); i++) { for (int i = 0; i < v.size(); i++) {
String line = v.elementAt(i).trim(); String line = v.elementAt(i).trim();
if (line.equalsIgnoreCase("[realms]")) { if (line.equalsIgnoreCase("[realms]")) {
@ -598,7 +598,7 @@ public class Config {
if ((count == v.size()) || if ((count == v.size()) ||
(v.elementAt(count).startsWith("["))) { (v.elementAt(count).startsWith("["))) {
Hashtable<String,Hashtable<String,Vector<String>>> temp = Hashtable<String,Hashtable<String,Vector<String>>> temp =
new Hashtable<String,Hashtable<String,Vector<String>>>(); new Hashtable<>();
temp = parseRealmField(v, i + 1, count); temp = parseRealmField(v, i + 1, count);
table.put("realms", temp); table.put("realms", temp);
i = count - 1; i = count - 1;
@ -611,7 +611,7 @@ public class Config {
if ((count == v.size()) || if ((count == v.size()) ||
(v.elementAt(count).startsWith("["))) { (v.elementAt(count).startsWith("["))) {
Hashtable<String,Hashtable<String,Vector<String>>> temp = Hashtable<String,Hashtable<String,Vector<String>>> temp =
new Hashtable<String,Hashtable<String,Vector<String>>>(); new Hashtable<>();
temp = parseRealmField(v, i + 1, count); temp = parseRealmField(v, i + 1, count);
table.put("capaths", temp); table.put("capaths", temp);
i = count - 1; i = count - 1;
@ -729,7 +729,7 @@ public class Config {
* Parses key-value pairs under a stanza name. * Parses key-value pairs under a stanza name.
*/ */
private Hashtable<String,String> parseField(Vector<String> v, int start, int end) { private Hashtable<String,String> parseField(Vector<String> v, int start, int end) {
Hashtable<String,String> table = new Hashtable<String,String> (); Hashtable<String,String> table = new Hashtable<>();
String line; String line;
for (int i = start; i < end; i++) { for (int i = start; i < end; i++) {
line = v.elementAt(i); line = v.elementAt(i);
@ -751,7 +751,7 @@ public class Config {
* information for the realm given within a pair of braces. * information for the realm given within a pair of braces.
*/ */
private Hashtable<String,Hashtable<String,Vector<String>>> parseRealmField(Vector<String> v, int start, int end) { private Hashtable<String,Hashtable<String,Vector<String>>> parseRealmField(Vector<String> v, int start, int end) {
Hashtable<String,Hashtable<String,Vector<String>>> table = new Hashtable<String,Hashtable<String,Vector<String>>> (); Hashtable<String,Hashtable<String,Vector<String>>> table = new Hashtable<>();
String line; String line;
for (int i = start; i < end; i++) { for (int i = start; i < end; i++) {
line = v.elementAt(i).trim(); line = v.elementAt(i).trim();
@ -791,10 +791,9 @@ public class Config {
* Parses key-value pairs within each braces under [realms]. * Parses key-value pairs within each braces under [realms].
*/ */
private Hashtable<String,Vector<String>> parseRealmFieldEx(Vector<String> v, int start, int end) { private Hashtable<String,Vector<String>> parseRealmFieldEx(Vector<String> v, int start, int end) {
Hashtable<String,Vector<String>> table = Hashtable<String,Vector<String>> table = new Hashtable<>();
new Hashtable<String,Vector<String>> (); Vector<String> keyVector = new Vector<>();
Vector<String> keyVector = new Vector<String> (); Vector<String> nameVector = new Vector<>();
Vector<String> nameVector = new Vector<String> ();
String line = ""; String line = "";
String key; String key;
for (int i = start; i < end; i++) { for (int i = start; i < end; i++) {
@ -899,7 +898,7 @@ public class Config {
} }
st = new StringTokenizer(default_enctypes, delim); st = new StringTokenizer(default_enctypes, delim);
int len = st.countTokens(); int len = st.countTokens();
ArrayList<Integer> ls = new ArrayList<Integer> (len); ArrayList<Integer> ls = new ArrayList<>(len);
int type; int type;
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
type = getType(st.nextToken()); type = getType(st.nextToken());

View File

@ -462,7 +462,7 @@ public final class KdcComm {
*/ */
static class KdcAccessibility { static class KdcAccessibility {
// Known bad KDCs // Known bad KDCs
private static Set<String> bads = new HashSet<String>(); private static Set<String> bads = new HashSet<>();
private static synchronized void addBad(String kdc) { private static synchronized void addBad(String kdc) {
if (DEBUG) { if (DEBUG) {
@ -492,9 +492,9 @@ public final class KdcComm {
// Returns a preferred KDC list by putting the bad ones at the end // Returns a preferred KDC list by putting the bad ones at the end
private static synchronized String[] list(String kdcList) { private static synchronized String[] list(String kdcList) {
StringTokenizer st = new StringTokenizer(kdcList); StringTokenizer st = new StringTokenizer(kdcList);
List<String> list = new ArrayList<String>(); List<String> list = new ArrayList<>();
if (badPolicy == BpType.TRY_LAST) { if (badPolicy == BpType.TRY_LAST) {
List<String> badkdcs = new ArrayList<String>(); List<String> badkdcs = new ArrayList<>();
while (st.hasMoreTokens()) { while (st.hasMoreTokens()) {
String t = st.nextToken(); String t = st.nextToken();
if (bads.contains(t)) badkdcs.add(t); if (bads.contains(t)) badkdcs.add(t);

View File

@ -244,7 +244,7 @@ public class PrincipalName
if (subDer.getTag() != DerValue.tag_SequenceOf) { if (subDer.getTag() != DerValue.tag_SequenceOf) {
throw new Asn1Exception(Krb5.ASN1_BAD_ID); throw new Asn1Exception(Krb5.ASN1_BAD_ID);
} }
Vector<String> v = new Vector<String> (); Vector<String> v = new Vector<>();
DerValue subSubDer; DerValue subSubDer;
while(subDer.getData().available() > 0) { while(subDer.getData().available() > 0) {
subSubDer = subDer.getData().getDerValue(); subSubDer = subDer.getData().getDerValue();
@ -299,7 +299,7 @@ public class PrincipalName
// Code repetition, realm parsed again by class Realm // Code repetition, realm parsed again by class Realm
protected static String[] parseName(String name) { protected static String[] parseName(String name) {
Vector<String> tempStrings = new Vector<String> (); Vector<String> tempStrings = new Vector<>();
String temp = name; String temp = name;
int i = 0; int i = 0;
int componentStart = 0; int componentStart = 0;

View File

@ -359,12 +359,12 @@ public class Realm implements Cloneable {
} }
String tempTarget = null, tempRealm = null; String tempTarget = null, tempRealm = null;
Stack<String> iStack = new Stack<String> (); Stack<String> iStack = new Stack<>();
/* /*
* I don't expect any more than a handful of intermediaries. * I don't expect any more than a handful of intermediaries.
*/ */
Vector<String> tempList = new Vector<String> (8, 8); Vector<String> tempList = new Vector<>(8, 8);
/* /*
* The initiator at first location. * The initiator at first location.

View File

@ -176,7 +176,7 @@ public class Authenticator {
* @exception IOException if an I/O error occurs while reading encoded data. * @exception IOException if an I/O error occurs while reading encoded data.
*/ */
public byte[] asn1Encode() throws Asn1Exception, IOException { public byte[] asn1Encode() throws Asn1Exception, IOException {
Vector<DerValue> v = new Vector<DerValue>(); Vector<DerValue> v = new Vector<>();
DerOutputStream temp = new DerOutputStream(); DerOutputStream temp = new DerOutputStream();
temp.putInteger(BigInteger.valueOf(authenticator_vno)); temp.putInteger(BigInteger.valueOf(authenticator_vno));
v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x00), temp.toByteArray())); v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0x00), temp.toByteArray()));

View File

@ -99,8 +99,7 @@ public class AuthorizationData implements Cloneable {
* @exception IOException if an I/O error occurs while reading encoded data. * @exception IOException if an I/O error occurs while reading encoded data.
*/ */
public AuthorizationData(DerValue der) throws Asn1Exception, IOException { public AuthorizationData(DerValue der) throws Asn1Exception, IOException {
Vector<AuthorizationDataEntry> v = Vector<AuthorizationDataEntry> v = new Vector<>();
new Vector<AuthorizationDataEntry>();
if (der.getTag() != DerValue.tag_Sequence) { if (der.getTag() != DerValue.tag_Sequence) {
throw new Asn1Exception(Krb5.ASN1_BAD_ID); throw new Asn1Exception(Krb5.ASN1_BAD_ID);
} }

View File

@ -133,7 +133,7 @@ public class EncAPRepPart {
* @exception IOException if an I/O error occurs while reading encoded data. * @exception IOException if an I/O error occurs while reading encoded data.
*/ */
public byte[] asn1Encode() throws Asn1Exception, IOException { public byte[] asn1Encode() throws Asn1Exception, IOException {
Vector<DerValue> v = new Vector<DerValue>(); Vector<DerValue> v = new Vector<>();
DerOutputStream temp = new DerOutputStream(); DerOutputStream temp = new DerOutputStream();
v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT,
true, (byte) 0x00), ctime.asn1Encode())); true, (byte) 0x00), ctime.asn1Encode()));

View File

@ -179,7 +179,7 @@ public class HostAddresses implements Cloneable {
*/ */
public HostAddresses(DerValue encoding) public HostAddresses(DerValue encoding)
throws Asn1Exception, IOException { throws Asn1Exception, IOException {
Vector<HostAddress> tempAddresses = new Vector<HostAddress> (); Vector<HostAddress> tempAddresses = new Vector<>();
DerValue der = null; DerValue der = null;
while (encoding.getData().available() > 0) { while (encoding.getData().available() > 0) {
der = encoding.getData().getDerValue(); der = encoding.getData().getDerValue();
@ -265,8 +265,7 @@ public class HostAddresses implements Cloneable {
if (addresses == null || addresses.length == 0) if (addresses == null || addresses.length == 0)
return null; return null;
ArrayList<InetAddress> ipAddrs = ArrayList<InetAddress> ipAddrs = new ArrayList<>(addresses.length);
new ArrayList<InetAddress> (addresses.length);
for (int i = 0; i < addresses.length; i++) { for (int i = 0; i < addresses.length; i++) {
try { try {

View File

@ -150,7 +150,7 @@ public class KDCReq {
if (subsubDer.getTag() != DerValue.tag_SequenceOf) { if (subsubDer.getTag() != DerValue.tag_SequenceOf) {
throw new Asn1Exception(Krb5.ASN1_BAD_ID); throw new Asn1Exception(Krb5.ASN1_BAD_ID);
} }
Vector<PAData> v = new Vector<PAData>(); Vector<PAData> v = new Vector<>();
while (subsubDer.getData().available() > 0) { while (subsubDer.getData().available() > 0) {
v.addElement(new PAData(subsubDer.getData().getDerValue())); v.addElement(new PAData(subsubDer.getData().getDerValue()));
} }

View File

@ -158,7 +158,7 @@ public class KDCReqBody {
throw new Asn1Exception(Krb5.ASN1_BAD_ID); throw new Asn1Exception(Krb5.ASN1_BAD_ID);
} }
der = encoding.getData().getDerValue(); der = encoding.getData().getDerValue();
Vector<Integer> v = new Vector<Integer> (); Vector<Integer> v = new Vector<>();
if ((der.getTag() & (byte)0x1F) == (byte)0x08) { if ((der.getTag() & (byte)0x1F) == (byte)0x08) {
subDer = der.getData().getDerValue(); subDer = der.getData().getDerValue();
@ -183,7 +183,7 @@ public class KDCReqBody {
encAuthorizationData = EncryptedData.parse(encoding.getData(), (byte)0x0A, true); encAuthorizationData = EncryptedData.parse(encoding.getData(), (byte)0x0A, true);
} }
if (encoding.getData().available() > 0) { if (encoding.getData().available() > 0) {
Vector<Ticket> tempTickets = new Vector<Ticket> (); Vector<Ticket> tempTickets = new Vector<>();
der = encoding.getData().getDerValue(); der = encoding.getData().getDerValue();
if ((der.getTag() & (byte)0x1F) == (byte)0x0B) { if ((der.getTag() & (byte)0x1F) == (byte)0x0B) {
subDer = der.getData().getDerValue(); subDer = der.getData().getDerValue();
@ -216,7 +216,7 @@ public class KDCReqBody {
* *
*/ */
public byte[] asn1Encode(int msgType) throws Asn1Exception, IOException { public byte[] asn1Encode(int msgType) throws Asn1Exception, IOException {
Vector<DerValue> v = new Vector<DerValue> (); Vector<DerValue> v = new Vector<>();
v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), kdcOptions.asn1Encode())); v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), kdcOptions.asn1Encode()));
if (msgType == Krb5.KRB_AS_REQ) { if (msgType == Krb5.KRB_AS_REQ) {
if (cname != null) { if (cname != null) {

View File

@ -134,7 +134,7 @@ public class KRBCred {
if (subsubDer.getTag() != DerValue.tag_SequenceOf) { if (subsubDer.getTag() != DerValue.tag_SequenceOf) {
throw new Asn1Exception(Krb5.ASN1_BAD_ID); throw new Asn1Exception(Krb5.ASN1_BAD_ID);
} }
Vector<Ticket> v = new Vector<Ticket>(); Vector<Ticket> v = new Vector<>();
while (subsubDer.getData().available() > 0) { while (subsubDer.getData().available() > 0) {
v.addElement(new Ticket(subsubDer.getData().getDerValue())); v.addElement(new Ticket(subsubDer.getData().getDerValue()));
} }

View File

@ -260,7 +260,7 @@ public class KRBError implements java.io.Serializable {
private void parsePAData(byte[] data) private void parsePAData(byte[] data)
throws IOException, Asn1Exception { throws IOException, Asn1Exception {
DerValue derPA = new DerValue(data); DerValue derPA = new DerValue(data);
List<PAData> paList = new ArrayList<PAData>(); List<PAData> paList = new ArrayList<>();
while (derPA.data.available() > 0) { while (derPA.data.available() > 0) {
// read the PA-DATA // read the PA-DATA
DerValue tmp = derPA.data.getDerValue(); DerValue tmp = derPA.data.getDerValue();

View File

@ -157,7 +157,7 @@ public class KrbCredInfo {
* @exception IOException if an I/O error occurs while reading encoded data. * @exception IOException if an I/O error occurs while reading encoded data.
*/ */
public byte[] asn1Encode() throws Asn1Exception, IOException { public byte[] asn1Encode() throws Asn1Exception, IOException {
Vector<DerValue> v = new Vector<DerValue> (); Vector<DerValue> v = new Vector<>();
v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), key.asn1Encode())); v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), key.asn1Encode()));
if (prealm != null) if (prealm != null)
v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), prealm.asn1Encode())); v.addElement(new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), prealm.asn1Encode()));

View File

@ -77,7 +77,7 @@ public class LastReq {
*/ */
public LastReq(DerValue encoding) throws Asn1Exception, IOException { public LastReq(DerValue encoding) throws Asn1Exception, IOException {
Vector<LastReqEntry> v= new Vector<LastReqEntry> (); Vector<LastReqEntry> v= new Vector<>();
if (encoding.getTag() != DerValue.tag_Sequence) { if (encoding.getTag() != DerValue.tag_Sequence) {
throw new Asn1Exception(Krb5.ASN1_BAD_ID); throw new Asn1Exception(Krb5.ASN1_BAD_ID);
} }

View File

@ -490,7 +490,7 @@ public class FileCredentialsCache extends CredentialsCache
private static String exec(String c) { private static String exec(String c) {
StringTokenizer st = new StringTokenizer(c); StringTokenizer st = new StringTokenizer(c);
Vector<String> v = new Vector<String> (); Vector<String> v = new Vector<>();
while (st.hasMoreTokens()) { while (st.hasMoreTokens()) {
v.addElement(st.nextToken()); v.addElement(st.nextToken());
} }

View File

@ -257,7 +257,7 @@ public abstract class EType {
+ configName); + configName);
} }
List<Integer> list = new ArrayList<Integer> (answer.length); List<Integer> list = new ArrayList<>(answer.length);
for (int i = 0; i < answer.length; i++) { for (int i = 0; i < answer.length; i++) {
if (EncryptionKey.findKey(answer[i], keys) != null) { if (EncryptionKey.findKey(answer[i], keys) != null) {
list.add(answer[i]); list.add(answer[i]);

View File

@ -57,7 +57,7 @@ public class KeyTab implements KeyTabConstants {
private static KeyTab singleton = null; private static KeyTab singleton = null;
private static final boolean DEBUG = Krb5.DEBUG; private static final boolean DEBUG = Krb5.DEBUG;
private static String name; private static String name;
private Vector<KeyTabEntry> entries = new Vector<KeyTabEntry> (); private Vector<KeyTabEntry> entries = new Vector<>();
private KeyTab(String filename) throws IOException, RealmException { private KeyTab(String filename) throws IOException, RealmException {
init(filename); init(filename);
@ -240,7 +240,7 @@ public class KeyTab implements KeyTabConstants {
KeyTabEntry entry; KeyTabEntry entry;
EncryptionKey key; EncryptionKey key;
int size = entries.size(); int size = entries.size();
ArrayList<EncryptionKey> keys = new ArrayList<EncryptionKey> (size); ArrayList<EncryptionKey> keys = new ArrayList<>(size);
for (int i = size-1; i >= 0; i--) { for (int i = size-1; i >= 0; i--) {
entry = entries.elementAt(i); entry = entries.elementAt(i);

View File

@ -123,19 +123,19 @@ public class JarSigner {
// or the default keystore, never null // or the default keystore, never null
String keystore; // key store file String keystore; // key store file
List<String> crlfiles = new ArrayList<String>(); // CRL files to add List<String> crlfiles = new ArrayList<>(); // CRL files to add
boolean nullStream = false; // null keystore input stream (NONE) boolean nullStream = false; // null keystore input stream (NONE)
boolean token = false; // token-based keystore boolean token = false; // token-based keystore
String jarfile; // jar files to sign or verify String jarfile; // jar files to sign or verify
String alias; // alias to sign jar with String alias; // alias to sign jar with
List<String> ckaliases = new ArrayList<String>(); // aliases in -verify List<String> ckaliases = new ArrayList<>(); // aliases in -verify
char[] storepass; // keystore password char[] storepass; // keystore password
boolean protectedPath; // protected authentication path boolean protectedPath; // protected authentication path
String storetype; // keystore type String storetype; // keystore type
String providerName; // provider name String providerName; // provider name
Vector<String> providers = null; // list of providers Vector<String> providers = null; // list of providers
// arguments for provider constructors // arguments for provider constructors
HashMap<String,String> providerArgs = new HashMap<String, String>(); HashMap<String,String> providerArgs = new HashMap<>();
char[] keypass; // private key password char[] keypass; // private key password
String sigfile; // name of .SF file String sigfile; // name of .SF file
String sigalg; // name of signature algorithm String sigalg; // name of signature algorithm
@ -236,7 +236,7 @@ public class JarSigner {
if (crlfiles.size() > 0 || autoCRL) { if (crlfiles.size() > 0 || autoCRL) {
CertificateFactory fac = CertificateFactory fac =
CertificateFactory.getInstance("X509"); CertificateFactory.getInstance("X509");
List<CRL> list = new ArrayList<CRL>(); List<CRL> list = new ArrayList<>();
for (String file: crlfiles) { for (String file: crlfiles) {
Collection<? extends CRL> tmp = KeyTool.loadCRLs(file); Collection<? extends CRL> tmp = KeyTool.loadCRLs(file);
for (CRL crl: tmp) { for (CRL crl: tmp) {
@ -606,7 +606,7 @@ public class JarSigner {
try { try {
jf = new JarFile(jarName, true); jf = new JarFile(jarName, true);
Vector<JarEntry> entriesVec = new Vector<JarEntry>(); Vector<JarEntry> entriesVec = new Vector<>();
byte[] buffer = new byte[8192]; byte[] buffer = new byte[8192];
Enumeration<JarEntry> entries = jf.entries(); Enumeration<JarEntry> entries = jf.entries();
@ -633,8 +633,7 @@ public class JarSigner {
// The map to record display info, only used when -verbose provided // The map to record display info, only used when -verbose provided
// key: signer info string // key: signer info string
// value: the list of files with common key // value: the list of files with common key
Map<String,List<String>> output = Map<String,List<String>> output = new LinkedHashMap<>();
new LinkedHashMap<String,List<String>>();
if (man != null) { if (man != null) {
if (verbose != null) System.out.println(); if (verbose != null) System.out.println();
@ -1000,8 +999,7 @@ public class JarSigner {
.append(signTimeForm.format(source)).append("]").toString(); .append(signTimeForm.format(source)).append("]").toString();
} }
private Map<CodeSigner,Integer> cacheForInKS = private Map<CodeSigner,Integer> cacheForInKS = new IdentityHashMap<>();
new IdentityHashMap<CodeSigner,Integer>();
private int inKeyStoreForOneSigner(CodeSigner signer) { private int inKeyStoreForOneSigner(CodeSigner signer) {
if (cacheForInKS.containsKey(signer)) { if (cacheForInKS.containsKey(signer)) {
@ -1044,8 +1042,7 @@ public class JarSigner {
return result; return result;
} }
Hashtable<Certificate, String> storeHash = Hashtable<Certificate, String> storeHash = new Hashtable<>();
new Hashtable<Certificate, String>();
int inKeyStore(CodeSigner[] signers) { int inKeyStore(CodeSigner[] signers) {
@ -1175,7 +1172,7 @@ public class JarSigner {
* generated one. (This may invalidate existing signatures!) * generated one. (This may invalidate existing signatures!)
*/ */
BASE64Encoder encoder = new JarBASE64Encoder(); BASE64Encoder encoder = new JarBASE64Encoder();
Vector<ZipEntry> mfFiles = new Vector<ZipEntry>(); Vector<ZipEntry> mfFiles = new Vector<>();
boolean wasSigned = false; boolean wasSigned = false;
@ -1531,7 +1528,7 @@ public class JarSigner {
return false; return false;
} }
Map<CodeSigner,String> cacheForSignerInfo = new IdentityHashMap<CodeSigner,String>(); Map<CodeSigner,String> cacheForSignerInfo = new IdentityHashMap<>();
/** /**
* Returns a string of singer info, with a newline at the end * Returns a string of singer info, with a newline at the end
@ -1655,7 +1652,7 @@ public class JarSigner {
} }
} }
} }
Set<TrustAnchor> tas = new HashSet<TrustAnchor>(); Set<TrustAnchor> tas = new HashSet<>();
try { try {
KeyStore caks = KeyTool.getCacertsKeyStore(); KeyStore caks = KeyTool.getCacertsKeyStore();
if (caks != null) { if (caks != null) {

View File

@ -153,11 +153,11 @@ public final class KeyTool {
private KeyStore caks = null; // "cacerts" keystore private KeyStore caks = null; // "cacerts" keystore
private char[] srcstorePass = null; private char[] srcstorePass = null;
private String srcstoretype = null; private String srcstoretype = null;
private Set<char[]> passwords = new HashSet<char[]> (); private Set<char[]> passwords = new HashSet<>();
private String startDate = null; private String startDate = null;
private List <String> ids = new ArrayList <String> (); // used in GENCRL private List<String> ids = new ArrayList<>(); // used in GENCRL
private List <String> v3ext = new ArrayList <String> (); private List<String> v3ext = new ArrayList<>();
enum Command { enum Command {
CERTREQ("Generates.a.certificate.request", CERTREQ("Generates.a.certificate.request",
@ -2091,7 +2091,7 @@ public final class KeyTool {
*/ */
public static List<CRL> readCRLsFromCert(X509Certificate cert) public static List<CRL> readCRLsFromCert(X509Certificate cert)
throws Exception { throws Exception {
List<CRL> crls = new ArrayList<CRL>(); List<CRL> crls = new ArrayList<>();
CRLDistributionPointsExtension ext = CRLDistributionPointsExtension ext =
X509CertImpl.toImpl(cert).getCRLDistributionPointsExtension(); X509CertImpl.toImpl(cert).getCRLDistributionPointsExtension();
if (ext == null) return crls; if (ext == null) return crls;
@ -2258,7 +2258,7 @@ public final class KeyTool {
if (jarfile != null) { if (jarfile != null) {
JarFile jf = new JarFile(jarfile, true); JarFile jf = new JarFile(jarfile, true);
Enumeration<JarEntry> entries = jf.entries(); Enumeration<JarEntry> entries = jf.entries();
Set<CodeSigner> ss = new HashSet<CodeSigner>(); Set<CodeSigner> ss = new HashSet<>();
byte[] buffer = new byte[8192]; byte[] buffer = new byte[8192];
int pos = 0; int pos = 0;
while (entries.hasMoreElements()) { while (entries.hasMoreElements()) {
@ -3347,7 +3347,7 @@ public final class KeyTool {
} }
// start building chain // start building chain
Vector<Certificate> chain = new Vector<Certificate>(2); Vector<Certificate> chain = new Vector<>(2);
if (buildChain((X509Certificate)certToVerify, chain, certs)) { if (buildChain((X509Certificate)certToVerify, chain, certs)) {
Certificate[] newChain = new Certificate[chain.size()]; Certificate[] newChain = new Certificate[chain.size()];
// buildChain() returns chain with self-signed root-cert first and // buildChain() returns chain with self-signed root-cert first and
@ -3873,8 +3873,7 @@ public final class KeyTool {
break; break;
case 2: // EKU case 2: // EKU
if(value != null) { if(value != null) {
Vector <ObjectIdentifier> v = Vector<ObjectIdentifier> v = new Vector<>();
new Vector <ObjectIdentifier>();
for (String s: value.split(",")) { for (String s: value.split(",")) {
int p = oneOf(s, int p = oneOf(s,
"anyExtendedKeyUsage", "anyExtendedKeyUsage",
@ -3944,7 +3943,7 @@ public final class KeyTool {
} }
if(value != null) { if(value != null) {
List<AccessDescription> accessDescriptions = List<AccessDescription> accessDescriptions =
new ArrayList<AccessDescription>(); new ArrayList<>();
String[] ps = value.split(","); String[] ps = value.split(",");
for(String item: ps) { for(String item: ps) {
colonpos = item.indexOf(':'); colonpos = item.indexOf(':');
@ -4228,7 +4227,7 @@ class Pair<A, B> {
} }
public static <A,B> Pair<A,B> of(A a, B b) { public static <A,B> Pair<A,B> of(A a, B b) {
return new Pair<A,B>(a,b); return new Pair<>(a,b);
} }
} }

View File

@ -643,7 +643,7 @@ public class PolicyTool {
Class<?> pc = Class.forName(type, true, Class<?> pc = Class.forName(type, true,
Thread.currentThread().getContextClassLoader()); Thread.currentThread().getContextClassLoader());
Constructor<?> c = null; Constructor<?> c = null;
Vector<String> objects = new Vector<String>(2); Vector<String> objects = new Vector<>(2);
if (name != null) objects.add(name); if (name != null) objects.add(name);
if (actions != null) objects.add(actions); if (actions != null) objects.add(actions);
switch (objects.size()) { switch (objects.size()) {
@ -1722,8 +1722,7 @@ class ToolDialog extends Dialog {
new PolicyParser.GrantEntry(signedby, codebase); new PolicyParser.GrantEntry(signedby, codebase);
// get the new Principals // get the new Principals
LinkedList<PolicyParser.PrincipalEntry> prins = LinkedList<PolicyParser.PrincipalEntry> prins = new LinkedList<>();
new LinkedList<PolicyParser.PrincipalEntry>();
TaggedList prinList = (TaggedList)getComponent(PE_PRIN_LIST); TaggedList prinList = (TaggedList)getComponent(PE_PRIN_LIST);
for (int i = 0; i < prinList.getItemCount(); i++) { for (int i = 0; i < prinList.getItemCount(); i++) {
prins.add((PolicyParser.PrincipalEntry)prinList.getObject(i)); prins.add((PolicyParser.PrincipalEntry)prinList.getObject(i));
@ -1731,8 +1730,7 @@ class ToolDialog extends Dialog {
ge.principals = prins; ge.principals = prins;
// get the new Permissions // get the new Permissions
Vector<PolicyParser.PermissionEntry> perms = Vector<PolicyParser.PermissionEntry> perms = new Vector<>();
new Vector<PolicyParser.PermissionEntry>();
TaggedList permList = (TaggedList)getComponent(PE_PERM_LIST); TaggedList permList = (TaggedList)getComponent(PE_PERM_LIST);
for (int i = 0; i < permList.getItemCount(); i++) { for (int i = 0; i < permList.getItemCount(); i++) {
perms.addElement((PolicyParser.PermissionEntry)permList.getObject(i)); perms.addElement((PolicyParser.PermissionEntry)permList.getObject(i));
@ -3649,7 +3647,7 @@ class NoDisplayException extends RuntimeException {
* This is a java.awt.List that bind an Object to each String it holds. * This is a java.awt.List that bind an Object to each String it holds.
*/ */
class TaggedList extends List { class TaggedList extends List {
private java.util.List<Object> data = new LinkedList<Object>(); private java.util.List<Object> data = new LinkedList<>();
public TaggedList(int i, boolean b) { public TaggedList(int i, boolean b) {
super(i, b); super(i, b);
} }

View File

@ -209,7 +209,7 @@ createNewJPLISAgent(JavaVM * vm, JPLISAgent **agent_ptr) {
*agent_ptr = NULL; *agent_ptr = NULL;
jnierror = (*vm)->GetEnv( vm, jnierror = (*vm)->GetEnv( vm,
(void **) &jvmtienv, (void **) &jvmtienv,
JVMTI_VERSION); JVMTI_VERSION_1_1);
if ( jnierror != JNI_OK ) { if ( jnierror != JNI_OK ) {
initerror = JPLIS_INIT_ERROR_CANNOT_CREATE_NATIVE_AGENT; initerror = JPLIS_INIT_ERROR_CANNOT_CREATE_NATIVE_AGENT;
} else { } else {
@ -990,7 +990,7 @@ retransformableEnvironment(JPLISAgent * agent) {
} }
jnierror = (*agent->mJVM)->GetEnv( agent->mJVM, jnierror = (*agent->mJVM)->GetEnv( agent->mJVM,
(void **) &retransformerEnv, (void **) &retransformerEnv,
JVMTI_VERSION); JVMTI_VERSION_1_1);
if ( jnierror != JNI_OK ) { if ( jnierror != JNI_OK ) {
return NULL; return NULL;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -41,8 +41,9 @@ enum {
JVMTI_VERSION_1 = 0x30010000, JVMTI_VERSION_1 = 0x30010000,
JVMTI_VERSION_1_0 = 0x30010000, JVMTI_VERSION_1_0 = 0x30010000,
JVMTI_VERSION_1_1 = 0x30010100, JVMTI_VERSION_1_1 = 0x30010100,
JVMTI_VERSION_1_2 = 0x30010200,
JVMTI_VERSION = 0x30000000 + (1 * 0x10000) + (1 * 0x100) + 102 /* version: 1.1.102 */ JVMTI_VERSION = 0x30000000 + (1 * 0x10000) + (2 * 0x100) + 1 /* version: 1.2.1 */
}; };
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
@ -1774,6 +1775,12 @@ typedef struct jvmtiInterface_1_ {
jobject object, jobject object,
jlong* size_ptr); jlong* size_ptr);
/* 155 : Get Local Instance */
jvmtiError (JNICALL *GetLocalInstance) (jvmtiEnv* env,
jthread thread,
jint depth,
jobject* value_ptr);
} jvmtiInterface_1; } jvmtiInterface_1;
struct _jvmtiEnv { struct _jvmtiEnv {
@ -2031,6 +2038,12 @@ struct _jvmtiEnv {
return functions->GetLocalObject(this, thread, depth, slot, value_ptr); return functions->GetLocalObject(this, thread, depth, slot, value_ptr);
} }
jvmtiError GetLocalInstance(jthread thread,
jint depth,
jobject* value_ptr) {
return functions->GetLocalInstance(this, thread, depth, value_ptr);
}
jvmtiError GetLocalInt(jthread thread, jvmtiError GetLocalInt(jthread thread,
jint depth, jint depth,
jint slot, jint slot,
@ -2518,3 +2531,4 @@ struct _jvmtiEnv {
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif /* !_JAVA_JVMTI_H_ */ #endif /* !_JAVA_JVMTI_H_ */

View File

@ -734,8 +734,8 @@ java/util/concurrent/locks/Lock/TimedAcquireLeak.java generic-all
# Fails on solaris-sparc -server (Set not equal to copy. 1) # Fails on solaris-sparc -server (Set not equal to copy. 1)
java/util/EnumSet/EnumSetBash.java solaris-sparc java/util/EnumSet/EnumSetBash.java solaris-sparc
# Need to be marked othervm, or changed to be samevm safe # Fails on solaris-sparc, see 7011857
java/util/WeakHashMap/GCDuringIteration.java generic-all java/util/concurrent/Phaser/FickleRegister.java solaris-sparc
############################################################################ ############################################################################

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6426034
* @summary Instance filter doesn't filter event if it occurs in native method
*
* @author Keith McGuigan
*
* @library scaffold
* @run build JDIScaffold VMConnection
* @compile -XDignore.symbol.file NativeInstanceFilterTarg.java
* @run main/othervm NativeInstanceFilter
*/
/*
* This test tests instance filters for events generated from a native method
*/
import java.util.*;
import com.sun.jdi.*;
import com.sun.jdi.event.*;
import com.sun.jdi.request.*;
public class NativeInstanceFilter extends JDIScaffold {
static int unfilteredEvents = 0;
public static void main(String args[]) throws Exception {
new NativeInstanceFilter().startTests();
}
public NativeInstanceFilter() {
super();
}
static EventRequestManager requestManager = null;
static MethodExitRequest request = null;
private void listen() {
TargetAdapter adapter = new TargetAdapter() {
EventSet set = null;
ObjectReference instance = null;
public boolean eventSetReceived(EventSet set) {
this.set = set;
return false;
}
public boolean methodExited(MethodExitEvent event) {
String name = event.method().name();
if (instance == null && name.equals("latch")) {
// Grab the instance (return value) and set up as filter
System.out.println("Setting up instance filter");
instance = (ObjectReference)event.returnValue();
requestManager.deleteEventRequest(request);
request = requestManager.createMethodExitRequest();
request.addInstanceFilter(instance);
request.enable();
} else if (instance != null && name.equals("intern")) {
// If not for the filter, this will be called twice
System.out.println("method exit event (String.intern())");
++unfilteredEvents;
}
set.resume();
return false;
}
};
addListener(adapter);
}
protected void runTests() throws Exception {
String[] args = new String[2];
args[0] = "-connect";
args[1] = "com.sun.jdi.CommandLineLaunch:main=NativeInstanceFilterTarg";
connect(args);
waitForVMStart();
// VM has started, but hasn't started running the test program yet.
requestManager = vm().eventRequestManager();
ReferenceType referenceType =
resumeToPrepareOf("NativeInstanceFilterTarg").referenceType();
request = requestManager.createMethodExitRequest();
request.enable();
listen();
vm().resume();
waitForVMDeath();
if (unfilteredEvents != 1) {
throw new Exception(
"Failed: Event from native frame not filtered out.");
}
System.out.println("Passed: Event filtered out.");
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import sun.misc.Version;
public class NativeInstanceFilterTarg {
public static void main(String args[]) {
boolean runTest = jvmSupportsJVMTI_12x();
String s1 = "abc";
String s2 = "def";
latch(s1);
s1.intern();
if (runTest) {
s2.intern(); // this is the call that generates events that ought
// to be filtered out.
} else {
System.out.println("Neutering test since JVMTI 1.2 not supported");
}
}
// Used by debugger to get an instance to filter with
public static String latch(String s) { return s; }
public static boolean jvmSupportsJVMTI_12x() {
// This fix requires the JVM to support JVMTI 1.2, which doesn't
// happen until HSX 20.0, build 05.
int major = Version.jvmMajorVersion();
int minor = Version.jvmMinorVersion();
int micro = Version.jvmMicroVersion();
int build = Version.jvmBuildNumber();
return (major > 20 || major == 20 &&
(minor > 0 || micro > 0 || build >= 5));
}
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6896088
* @run main/othervm B6896088
* @summary URLClassLoader.close() apparently not working for JAR URLs on Windows
*/
import java.net.*;
import java.io.*;
import java.nio.file.Path;
public class B6896088 {
public static void main(String[] args) throws Exception {
String dir = System.getProperty ("test.classes");
File jarf = new File (dir, "foo.jar");
FileOutputStream fos = new FileOutputStream (jarf);
fos.write(bytes(nums));
fos.close();
// Create URL using JAR protocol
String jarName = (jarf.toURI()).toString();
URL url = new URL("jar", "", jarName + "!/");
// Create URLClassLoader from the URL
URLClassLoader loader = new URLClassLoader(new URL[]{url});
Class c = loader.loadClass("Foo");
// Close the URLClassLoader so we can delete/update the jar file
loader.close();
// Now try to delete the jar file
if (jarf.delete() && !jarf.exists()) {
System.out.println(jarf.getName()+" File Deleted");
} else {
System.out.println(jarf.getName()+" File Not Deleted");
throw new RuntimeException ("File not deleted");
}
}
static byte[] bytes (int[] i) {
byte[] buf = new byte [i.length];
for (int j=0; j<i.length; j++) {
buf[j] = (byte)i[j];
}
return buf;
}
/* contents of foo.jar */
static final int nums[] = {
0x50,0x4b,0x03,0x04,0x14,0x00,0x08,0x08,0x08,0x00,0xc8,0x61,
0x90,0x3d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x09,0x00,0x04,0x00,0x4d,0x45,0x54,0x41,0x2d,0x49,
0x4e,0x46,0x2f,0xfe,0xca,0x00,0x00,0x03,0x00,0x50,0x4b,0x07,
0x08,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x50,0x4b,0x03,0x04,0x14,0x00,0x08,0x08,0x08,0x00,0xc8,
0x61,0x90,0x3d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x14,0x00,0x00,0x00,0x4d,0x45,0x54,0x41,0x2d,
0x49,0x4e,0x46,0x2f,0x4d,0x41,0x4e,0x49,0x46,0x45,0x53,0x54,
0x2e,0x4d,0x46,0xf3,0x4d,0xcc,0xcb,0x4c,0x4b,0x2d,0x2e,0xd1,
0x0d,0x4b,0x2d,0x2a,0xce,0xcc,0xcf,0xb3,0x52,0x30,0xd4,0x33,
0xe0,0xe5,0x72,0x2e,0x4a,0x4d,0x2c,0x49,0x4d,0xd1,0x75,0xaa,
0x04,0x09,0x98,0xeb,0x19,0xe8,0x66,0xe6,0x95,0xa4,0x16,0xe5,
0x25,0xe6,0x28,0x68,0xf8,0x17,0x25,0x26,0xe7,0xa4,0x2a,0x38,
0xe7,0x17,0x15,0xe4,0x17,0x25,0x96,0x00,0x35,0x69,0xf2,0x72,
0xf1,0x72,0x01,0x00,0x50,0x4b,0x07,0x08,0x4c,0xd8,0x5e,0x68,
0x49,0x00,0x00,0x00,0x4a,0x00,0x00,0x00,0x50,0x4b,0x03,0x04,
0x14,0x00,0x08,0x08,0x08,0x00,0xbd,0x61,0x90,0x3d,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x00,
0x00,0x00,0x46,0x6f,0x6f,0x2e,0x63,0x6c,0x61,0x73,0x73,0x3b,
0xf5,0x6f,0xd7,0x3e,0x06,0x06,0x06,0x63,0x06,0x5e,0x2e,0x06,
0x66,0x06,0x2e,0x76,0x06,0x6e,0x76,0x06,0x1e,0x46,0x06,0x36,
0x9b,0xcc,0xbc,0xcc,0x12,0x3b,0x46,0x06,0x66,0x0d,0xcd,0x30,
0x46,0x06,0x16,0xe7,0xfc,0x94,0x54,0x46,0x06,0x7e,0x9f,0xcc,
0xbc,0x54,0xbf,0xd2,0xdc,0xa4,0xd4,0xa2,0x90,0xc4,0xa4,0x1c,
0xa0,0x08,0x57,0x70,0x7e,0x69,0x51,0x72,0xaa,0x5b,0x26,0x88,
0xc3,0xe1,0x96,0x9f,0xaf,0x97,0x95,0x58,0x96,0xc8,0xc3,0xc0,
0xc2,0xc0,0x0a,0xd4,0x0b,0xe4,0x33,0x32,0x08,0x80,0x44,0xf4,
0x73,0x12,0xf3,0xd2,0xf5,0xfd,0x93,0xb2,0x52,0x93,0x4b,0x18,
0x14,0x19,0x98,0x80,0x76,0x81,0x00,0x23,0x10,0x02,0x95,0x02,
0x49,0x36,0x20,0x4f,0x16,0xcc,0x67,0x60,0x60,0xd5,0xda,0xce,
0xc0,0xb8,0x11,0x2c,0xcd,0x0e,0x24,0xd9,0xc0,0x82,0x20,0x29,
0x0e,0x20,0xcd,0xc4,0xc0,0x09,0x00,0x50,0x4b,0x07,0x08,0x3e,
0x0a,0xdc,0x88,0x98,0x00,0x00,0x00,0xb4,0x00,0x00,0x00,0x50,
0x4b,0x01,0x02,0x14,0x00,0x14,0x00,0x08,0x08,0x08,0x00,0xc8,
0x61,0x90,0x3d,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x09,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4d,0x45,0x54,
0x41,0x2d,0x49,0x4e,0x46,0x2f,0xfe,0xca,0x00,0x00,0x50,0x4b,
0x01,0x02,0x14,0x00,0x14,0x00,0x08,0x08,0x08,0x00,0xc8,0x61,
0x90,0x3d,0x4c,0xd8,0x5e,0x68,0x49,0x00,0x00,0x00,0x4a,0x00,
0x00,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3d,0x00,0x00,0x00,0x4d,0x45,0x54,0x41,
0x2d,0x49,0x4e,0x46,0x2f,0x4d,0x41,0x4e,0x49,0x46,0x45,0x53,
0x54,0x2e,0x4d,0x46,0x50,0x4b,0x01,0x02,0x14,0x00,0x14,0x00,
0x08,0x08,0x08,0x00,0xbd,0x61,0x90,0x3d,0x3e,0x0a,0xdc,0x88,
0x98,0x00,0x00,0x00,0xb4,0x00,0x00,0x00,0x09,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x00,
0x00,0x00,0x46,0x6f,0x6f,0x2e,0x63,0x6c,0x61,0x73,0x73,0x50,
0x4b,0x05,0x06,0x00,0x00,0x00,0x00,0x03,0x00,0x03,0x00,0xb4,
0x00,0x00,0x00,0x97,0x01,0x00,0x00,0x00,0x00,0x00
};
}

View File

@ -33,18 +33,17 @@ import java.util.*;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
public class GCDuringIteration { public class GCDuringIteration {
static void finalizeTillYouDrop() { private static void waitForFinalizersToRun() {
System.gc(); // Enqueue all finalizables for (int i = 0; i < 2; i++)
tryWaitForFinalizersToRun();
}
System.runFinalization(); // Drain finalizer queue private static void tryWaitForFinalizersToRun() {
// There may be a straggler finalizable object still being
// finalized by the dedicated finalizer thread. Enqueue one
// more finalizable object, and wait for it to be finalized.
final CountDownLatch latch = new CountDownLatch(1);
new Object() { protected void finalize() { latch.countDown(); }};
System.gc(); System.gc();
try { latch.await(); } final CountDownLatch fin = new CountDownLatch(1);
new Object() { protected void finalize() { fin.countDown(); }};
System.gc();
try { fin.await(); }
catch (InterruptedException ie) { throw new Error(ie); } catch (InterruptedException ie) { throw new Error(ie); }
} }
@ -101,7 +100,9 @@ public class GCDuringIteration {
{ {
int first = firstValue(map); int first = firstValue(map);
final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator(); final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator();
foos[first] = null; finalizeTillYouDrop(); foos[first] = null;
for (int i = 0; i < 10 && map.size() != first; i++)
tryWaitForFinalizersToRun();
equal(map.size(), first); equal(map.size(), first);
checkIterator(it, first-1); checkIterator(it, first-1);
equal(map.size(), first); equal(map.size(), first);
@ -113,11 +114,14 @@ public class GCDuringIteration {
final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator(); final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator();
it.next(); // protects first entry it.next(); // protects first entry
System.out.println(map.values()); System.out.println(map.values());
foos[first] = null; finalizeTillYouDrop(); foos[first] = null;
tryWaitForFinalizersToRun()
equal(map.size(), first+1); equal(map.size(), first+1);
System.out.println(map.values()); System.out.println(map.values());
checkIterator(it, first-1); checkIterator(it, first-1);
finalizeTillYouDrop(); // first entry no longer protected // first entry no longer protected
for (int i = 0; i < 10 && map.size() != first; i++)
tryWaitForFinalizersToRun();
equal(map.size(), first); equal(map.size(), first);
equal(firstValue(map), first-1); equal(firstValue(map), first-1);
} }
@ -127,12 +131,15 @@ public class GCDuringIteration {
final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator(); final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator();
it.next(); // protects first entry it.next(); // protects first entry
System.out.println(map.values()); System.out.println(map.values());
foos[first] = foos[first-1] = null; finalizeTillYouDrop(); foos[first] = foos[first-1] = null;
tryWaitForFinalizersToRun();
equal(map.size(), first); equal(map.size(), first);
equal(firstValue(map), first); equal(firstValue(map), first);
System.out.println(map.values()); System.out.println(map.values());
checkIterator(it, first-2); checkIterator(it, first-2);
finalizeTillYouDrop(); // first entry no longer protected // first entry no longer protected
for (int i = 0; i < 10 && map.size() != first-1; i++)
tryWaitForFinalizersToRun();
equal(map.size(), first-1); equal(map.size(), first-1);
equal(firstValue(map), first-2); equal(firstValue(map), first-2);
} }
@ -143,12 +150,15 @@ public class GCDuringIteration {
it.next(); // protects first entry it.next(); // protects first entry
it.hasNext(); // protects second entry it.hasNext(); // protects second entry
System.out.println(map.values()); System.out.println(map.values());
foos[first] = foos[first-1] = null; finalizeTillYouDrop(); foos[first] = foos[first-1] = null;
tryWaitForFinalizersToRun();
equal(firstValue(map), first); equal(firstValue(map), first);
equal(map.size(), first+1); equal(map.size(), first+1);
System.out.println(map.values()); System.out.println(map.values());
checkIterator(it, first-1); checkIterator(it, first-1);
finalizeTillYouDrop(); // first entry no longer protected // first entry no longer protected
for (int i = 0; i < 10 && map.size() != first-1; i++)
tryWaitForFinalizersToRun();
equal(map.size(), first-1); equal(map.size(), first-1);
equal(firstValue(map), first-2); equal(firstValue(map), first-2);
} }
@ -158,13 +168,16 @@ public class GCDuringIteration {
final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator(); final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator();
it.next(); // protects first entry it.next(); // protects first entry
System.out.println(map.values()); System.out.println(map.values());
foos[first] = foos[first-1] = null; finalizeTillYouDrop(); foos[first] = foos[first-1] = null;
tryWaitForFinalizersToRun();
it.remove(); it.remove();
equal(firstValue(map), first-2); equal(firstValue(map), first-2);
equal(map.size(), first-1); equal(map.size(), first-1);
System.out.println(map.values()); System.out.println(map.values());
checkIterator(it, first-2); checkIterator(it, first-2);
finalizeTillYouDrop(); // first entry no longer protected
for (int i = 0; i < 10 && map.size() != first-1; i++)
tryWaitForFinalizersToRun();
equal(map.size(), first-1); equal(map.size(), first-1);
equal(firstValue(map), first-2); equal(firstValue(map), first-2);
} }
@ -176,12 +189,14 @@ public class GCDuringIteration {
it.remove(); it.remove();
it.hasNext(); // protects second entry it.hasNext(); // protects second entry
System.out.println(map.values()); System.out.println(map.values());
foos[first] = foos[first-1] = null; finalizeTillYouDrop(); foos[first] = foos[first-1] = null;
tryWaitForFinalizersToRun();
equal(firstValue(map), first-1); equal(firstValue(map), first-1);
equal(map.size(), first); equal(map.size(), first);
System.out.println(map.values()); System.out.println(map.values());
checkIterator(it, first-1); checkIterator(it, first-1);
finalizeTillYouDrop(); for (int i = 0; i < 10 && map.size() != first-1; i++)
tryWaitForFinalizersToRun();
equal(map.size(), first-1); equal(map.size(), first-1);
equal(firstValue(map), first-2); equal(firstValue(map), first-2);
} }
@ -191,12 +206,13 @@ public class GCDuringIteration {
final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator(); final Iterator<Map.Entry<Foo,Integer>> it = map.entrySet().iterator();
it.hasNext(); // protects first entry it.hasNext(); // protects first entry
Arrays.fill(foos, null); Arrays.fill(foos, null);
finalizeTillYouDrop(); tryWaitForFinalizersToRun();
equal(map.size(), 1); equal(map.size(), 1);
System.out.println(map.values()); System.out.println(map.values());
equal(it.next().getValue(), first); equal(it.next().getValue(), first);
check(! it.hasNext()); check(! it.hasNext());
finalizeTillYouDrop(); for (int i = 0; i < 10 && map.size() != 0; i++)
tryWaitForFinalizersToRun();
equal(map.size(), 0); equal(map.size(), 0);
check(map.isEmpty()); check(map.isEmpty());
} }

View File

@ -34,7 +34,7 @@
/* /*
* @test * @test
* @bug 4486658 * @bug 4486658
* @compile CancelledProducerConsumerLoops.java * @compile -source 1.5 CancelledProducerConsumerLoops.java
* @run main/timeout=7000 CancelledProducerConsumerLoops * @run main/timeout=7000 CancelledProducerConsumerLoops
* @summary Checks for responsiveness of blocking queues to cancellation. * @summary Checks for responsiveness of blocking queues to cancellation.
* Runs under the assumption that ITERS computations require more than * Runs under the assumption that ITERS computations require more than
@ -119,48 +119,24 @@ public class CancelledProducerConsumerLoops {
} }
} }
static final class LTQasSQ<T> extends LinkedTransferQueue<T> {
LTQasSQ() { super(); }
public void put(T x) {
try { super.transfer(x); }
catch (InterruptedException ex) { throw new Error(); }
}
private final static long serialVersionUID = 42;
}
static final class HalfSyncLTQ<T> extends LinkedTransferQueue<T> {
HalfSyncLTQ() { super(); }
public void put(T x) {
if (ThreadLocalRandom.current().nextBoolean())
super.put(x);
else {
try { super.transfer(x); }
catch (InterruptedException ex) { throw new Error(); }
}
}
private final static long serialVersionUID = 42;
}
static void oneTest(int pairs, int iters) throws Exception { static void oneTest(int pairs, int iters) throws Exception {
oneRun(new ArrayBlockingQueue<Integer>(CAPACITY), pairs, iters); oneRun(new ArrayBlockingQueue<Integer>(CAPACITY), pairs, iters);
oneRun(new LinkedBlockingQueue<Integer>(CAPACITY), pairs, iters); oneRun(new LinkedBlockingQueue<Integer>(CAPACITY), pairs, iters);
oneRun(new LinkedBlockingDeque<Integer>(CAPACITY), pairs, iters); oneRun(new LinkedBlockingDeque<Integer>(CAPACITY), pairs, iters);
oneRun(new LinkedTransferQueue<Integer>(), pairs, iters);
oneRun(new SynchronousQueue<Integer>(), pairs, iters / 8); oneRun(new SynchronousQueue<Integer>(), pairs, iters / 8);
/* TODO: unbounded queue implementations are prone to OOME /* PriorityBlockingQueue is unbounded
oneRun(new PriorityBlockingQueue<Integer>(iters / 2 * pairs), pairs, iters / 4); oneRun(new PriorityBlockingQueue<Integer>(iters / 2 * pairs), pairs, iters / 4);
oneRun(new LinkedTransferQueue<Integer>(), pairs, iters);
oneRun(new LTQasSQ<Integer>(), pairs, iters);
oneRun(new HalfSyncLTQ<Integer>(), pairs, iters);
*/ */
} }
static abstract class Stage implements Callable<Integer> { abstract static class Stage implements Callable<Integer> {
final BlockingQueue<Integer> queue; final BlockingQueue<Integer> queue;
final CyclicBarrier barrier; final CyclicBarrier barrier;
final int iters; final int iters;
Stage (BlockingQueue<Integer> q, CyclicBarrier b, int iters) { Stage(BlockingQueue<Integer> q, CyclicBarrier b, int iters) {
queue = q; queue = q;
barrier = b; barrier = b;
this.iters = iters; this.iters = iters;

View File

@ -34,7 +34,7 @@
/* /*
* @test * @test
* @bug 4486658 * @bug 4486658
* @compile MultipleProducersSingleConsumerLoops.java * @compile -source 1.5 MultipleProducersSingleConsumerLoops.java
* @run main/timeout=3600 MultipleProducersSingleConsumerLoops * @run main/timeout=3600 MultipleProducersSingleConsumerLoops
* @summary multiple producers and single consumer using blocking queues * @summary multiple producers and single consumer using blocking queues
*/ */
@ -87,35 +87,11 @@ public class MultipleProducersSingleConsumerLoops {
throw new Error(); throw new Error();
} }
static final class LTQasSQ<T> extends LinkedTransferQueue<T> {
LTQasSQ() { super(); }
public void put(T x) {
try { super.transfer(x); }
catch (InterruptedException ex) { throw new Error(); }
}
private final static long serialVersionUID = 42;
}
static final class HalfSyncLTQ<T> extends LinkedTransferQueue<T> {
HalfSyncLTQ() { super(); }
public void put(T x) {
if (ThreadLocalRandom.current().nextBoolean())
super.put(x);
else {
try { super.transfer(x); }
catch (InterruptedException ex) { throw new Error(); }
}
}
private final static long serialVersionUID = 42;
}
static void oneTest(int producers, int iters) throws Exception { static void oneTest(int producers, int iters) throws Exception {
oneRun(new ArrayBlockingQueue<Integer>(CAPACITY), producers, iters); oneRun(new ArrayBlockingQueue<Integer>(CAPACITY), producers, iters);
oneRun(new LinkedBlockingQueue<Integer>(CAPACITY), producers, iters); oneRun(new LinkedBlockingQueue<Integer>(CAPACITY), producers, iters);
oneRun(new LinkedBlockingDeque<Integer>(CAPACITY), producers, iters); oneRun(new LinkedBlockingDeque<Integer>(CAPACITY), producers, iters);
oneRun(new LinkedTransferQueue<Integer>(), producers, iters); oneRun(new LinkedTransferQueue<Integer>(), producers, iters);
oneRun(new LTQasSQ<Integer>(), producers, iters);
oneRun(new HalfSyncLTQ<Integer>(), producers, iters);
// Don't run PBQ since can legitimately run out of memory // Don't run PBQ since can legitimately run out of memory
// if (print) // if (print)
@ -129,11 +105,11 @@ public class MultipleProducersSingleConsumerLoops {
oneRun(new ArrayBlockingQueue<Integer>(CAPACITY, true), producers, iters); oneRun(new ArrayBlockingQueue<Integer>(CAPACITY, true), producers, iters);
} }
static abstract class Stage implements Runnable { abstract static class Stage implements Runnable {
final int iters; final int iters;
final BlockingQueue<Integer> queue; final BlockingQueue<Integer> queue;
final CyclicBarrier barrier; final CyclicBarrier barrier;
Stage (BlockingQueue<Integer> q, CyclicBarrier b, int iters) { Stage(BlockingQueue<Integer> q, CyclicBarrier b, int iters) {
queue = q; queue = q;
barrier = b; barrier = b;
this.iters = iters; this.iters = iters;

View File

@ -34,7 +34,7 @@
/* /*
* @test * @test
* @bug 4486658 * @bug 4486658
* @compile ProducerConsumerLoops.java * @compile -source 1.5 ProducerConsumerLoops.java
* @run main/timeout=3600 ProducerConsumerLoops * @run main/timeout=3600 ProducerConsumerLoops
* @summary multiple producers and consumers using blocking queues * @summary multiple producers and consumers using blocking queues
*/ */
@ -87,35 +87,11 @@ public class ProducerConsumerLoops {
throw new Error(); throw new Error();
} }
static final class LTQasSQ<T> extends LinkedTransferQueue<T> {
LTQasSQ() { super(); }
public void put(T x) {
try { super.transfer(x); }
catch (InterruptedException ex) { throw new Error(); }
}
private final static long serialVersionUID = 42;
}
static final class HalfSyncLTQ<T> extends LinkedTransferQueue<T> {
HalfSyncLTQ() { super(); }
public void put(T x) {
if (ThreadLocalRandom.current().nextBoolean())
super.put(x);
else {
try { super.transfer(x); }
catch (InterruptedException ex) { throw new Error(); }
}
}
private final static long serialVersionUID = 42;
}
static void oneTest(int pairs, int iters) throws Exception { static void oneTest(int pairs, int iters) throws Exception {
oneRun(new ArrayBlockingQueue<Integer>(CAPACITY), pairs, iters); oneRun(new ArrayBlockingQueue<Integer>(CAPACITY), pairs, iters);
oneRun(new LinkedBlockingQueue<Integer>(CAPACITY), pairs, iters); oneRun(new LinkedBlockingQueue<Integer>(CAPACITY), pairs, iters);
oneRun(new LinkedBlockingDeque<Integer>(CAPACITY), pairs, iters); oneRun(new LinkedBlockingDeque<Integer>(CAPACITY), pairs, iters);
oneRun(new LinkedTransferQueue<Integer>(), pairs, iters); oneRun(new LinkedTransferQueue<Integer>(), pairs, iters);
oneRun(new LTQasSQ<Integer>(), pairs, iters);
oneRun(new HalfSyncLTQ<Integer>(), pairs, iters);
oneRun(new PriorityBlockingQueue<Integer>(), pairs, iters); oneRun(new PriorityBlockingQueue<Integer>(), pairs, iters);
oneRun(new SynchronousQueue<Integer>(), pairs, iters); oneRun(new SynchronousQueue<Integer>(), pairs, iters);
@ -126,11 +102,11 @@ public class ProducerConsumerLoops {
oneRun(new ArrayBlockingQueue<Integer>(CAPACITY, true), pairs, iters); oneRun(new ArrayBlockingQueue<Integer>(CAPACITY, true), pairs, iters);
} }
static abstract class Stage implements Runnable { abstract static class Stage implements Runnable {
final int iters; final int iters;
final BlockingQueue<Integer> queue; final BlockingQueue<Integer> queue;
final CyclicBarrier barrier; final CyclicBarrier barrier;
Stage (BlockingQueue<Integer> q, CyclicBarrier b, int iters) { Stage(BlockingQueue<Integer> q, CyclicBarrier b, int iters) {
queue = q; queue = q;
barrier = b; barrier = b;
this.iters = iters; this.iters = iters;

View File

@ -34,7 +34,7 @@
/* /*
* @test * @test
* @bug 4486658 * @bug 4486658
* @compile SingleProducerMultipleConsumerLoops.java * @compile -source 1.5 SingleProducerMultipleConsumerLoops.java
* @run main/timeout=600 SingleProducerMultipleConsumerLoops * @run main/timeout=600 SingleProducerMultipleConsumerLoops
* @summary check ordering for blocking queues with 1 producer and multiple consumers * @summary check ordering for blocking queues with 1 producer and multiple consumers
*/ */
@ -73,35 +73,11 @@ public class SingleProducerMultipleConsumerLoops {
throw new Error(); throw new Error();
} }
static final class LTQasSQ<T> extends LinkedTransferQueue<T> {
LTQasSQ() { super(); }
public void put(T x) {
try { super.transfer(x); }
catch (InterruptedException ex) { throw new Error(); }
}
private final static long serialVersionUID = 42;
}
static final class HalfSyncLTQ<T> extends LinkedTransferQueue<T> {
HalfSyncLTQ() { super(); }
public void put(T x) {
if (ThreadLocalRandom.current().nextBoolean())
super.put(x);
else {
try { super.transfer(x); }
catch (InterruptedException ex) { throw new Error(); }
}
}
private final static long serialVersionUID = 42;
}
static void oneTest(int consumers, int iters) throws Exception { static void oneTest(int consumers, int iters) throws Exception {
oneRun(new ArrayBlockingQueue<Integer>(CAPACITY), consumers, iters); oneRun(new ArrayBlockingQueue<Integer>(CAPACITY), consumers, iters);
oneRun(new LinkedBlockingQueue<Integer>(CAPACITY), consumers, iters); oneRun(new LinkedBlockingQueue<Integer>(CAPACITY), consumers, iters);
oneRun(new LinkedBlockingDeque<Integer>(CAPACITY), consumers, iters); oneRun(new LinkedBlockingDeque<Integer>(CAPACITY), consumers, iters);
oneRun(new LinkedTransferQueue<Integer>(), consumers, iters); oneRun(new LinkedTransferQueue<Integer>(), consumers, iters);
oneRun(new LTQasSQ<Integer>(), consumers, iters);
oneRun(new HalfSyncLTQ<Integer>(), consumers, iters);
oneRun(new PriorityBlockingQueue<Integer>(), consumers, iters); oneRun(new PriorityBlockingQueue<Integer>(), consumers, iters);
oneRun(new SynchronousQueue<Integer>(), consumers, iters); oneRun(new SynchronousQueue<Integer>(), consumers, iters);
if (print) if (print)
@ -110,12 +86,12 @@ public class SingleProducerMultipleConsumerLoops {
oneRun(new ArrayBlockingQueue<Integer>(CAPACITY, true), consumers, iters); oneRun(new ArrayBlockingQueue<Integer>(CAPACITY, true), consumers, iters);
} }
static abstract class Stage implements Runnable { abstract static class Stage implements Runnable {
final int iters; final int iters;
final BlockingQueue<Integer> queue; final BlockingQueue<Integer> queue;
final CyclicBarrier barrier; final CyclicBarrier barrier;
volatile int result; volatile int result;
Stage (BlockingQueue<Integer> q, CyclicBarrier b, int iters) { Stage(BlockingQueue<Integer> q, CyclicBarrier b, int iters) {
queue = q; queue = q;
barrier = b; barrier = b;
this.iters = iters; this.iters = iters;

View File

@ -53,7 +53,9 @@ public class IteratorWeakConsistency {
test(new LinkedTransferQueue()); test(new LinkedTransferQueue());
// Other concurrent queues (e.g. ArrayBlockingQueue) do not // Other concurrent queues (e.g. ArrayBlockingQueue) do not
// currently have weakly consistent iterators. // currently have weakly consistent iterators.
// test(new ArrayBlockingQueue(20)); // As of 2010-09, ArrayBlockingQueue passes this test, but
// does not fully implement weak consistency.
test(new ArrayBlockingQueue(20));
} }
void test(Queue q) { void test(Queue q) {

View File

@ -24,6 +24,7 @@
/* /*
* @test * @test
* @bug 6399443 * @bug 6399443
* @run main/othervm AutoShutdown
* @summary Check for auto-shutdown and gc of singleThreadExecutors * @summary Check for auto-shutdown and gc of singleThreadExecutors
* @author Martin Buchholz * @author Martin Buchholz
*/ */

View File

@ -52,15 +52,16 @@ public class Basic {
check(phaser.isTerminated()); check(phaser.isTerminated());
int unarriverParties = phaser.getUnarrivedParties(); int unarriverParties = phaser.getUnarrivedParties();
int registeredParties = phaser.getRegisteredParties(); int registeredParties = phaser.getRegisteredParties();
equal(phaser.arrive(), -1); int phase = phaser.getPhase();
equal(phaser.arriveAndDeregister(), -1); check(phase < 0);
equal(phaser.arriveAndAwaitAdvance(), -1); equal(phase, phaser.arrive());
equal(phaser.bulkRegister(10), -1); equal(phase, phaser.arriveAndDeregister());
equal(phaser.getPhase(), -1); equal(phase, phaser.arriveAndAwaitAdvance());
equal(phaser.register(), -1); equal(phase, phaser.bulkRegister(10));
equal(phase, phaser.register());
try { try {
equal(phaser.awaitAdvanceInterruptibly(0), -1); equal(phase, phaser.awaitAdvanceInterruptibly(0));
equal(phaser.awaitAdvanceInterruptibly(0, 10, SECONDS), -1); equal(phase, phaser.awaitAdvanceInterruptibly(0, 10, SECONDS));
} catch (Exception ie) { } catch (Exception ie) {
unexpected(ie); unexpected(ie);
} }
@ -94,10 +95,9 @@ public class Basic {
} }
int phase = atTheStartingGate.getPhase(); int phase = atTheStartingGate.getPhase();
equal(phase, atTheStartingGate.arrive()); equal(phase, atTheStartingGate.arrive());
int AwaitPhase = atTheStartingGate.awaitAdvanceInterruptibly(phase, int awaitPhase = atTheStartingGate.awaitAdvanceInterruptibly
10, (phase, 10, SECONDS);
SECONDS); if (expectNextPhase) check(awaitPhase == (phase + 1));
if (expectNextPhase) check(AwaitPhase == (phase + 1));
pass(); pass();
} catch (Throwable t) { } catch (Throwable t) {
@ -271,18 +271,19 @@ public class Basic {
// Phaser is terminated while threads are waiting // Phaser is terminated while threads are waiting
//---------------------------------------------------------------- //----------------------------------------------------------------
try { try {
Phaser phaser = new Phaser(3);
Iterator<Awaiter> awaiters = awaiterIterator(phaser);
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
Phaser phaser = new Phaser(3);
Iterator<Awaiter> awaiters = awaiterIterator(phaser);
Arriver a1 = awaiters.next(); a1.start(); Arriver a1 = awaiters.next(); a1.start();
Arriver a2 = awaiters.next(); a2.start(); Arriver a2 = awaiters.next(); a2.start();
toTheStartingGate(); toTheStartingGate();
while (phaser.getArrivedParties() < 2) Thread.yield(); while (phaser.getArrivedParties() < 2) Thread.yield();
equal(0, phaser.getPhase());
phaser.forceTermination(); phaser.forceTermination();
a1.join(); a1.join();
a2.join(); a2.join();
check(a1.phase == -1); equal(0 + Integer.MIN_VALUE, a1.phase);
check(a2.phase == -1); equal(0 + Integer.MIN_VALUE, a2.phase);
int arrivedParties = phaser.getArrivedParties(); int arrivedParties = phaser.getArrivedParties();
checkTerminated(phaser); checkTerminated(phaser);
equal(phaser.getArrivedParties(), arrivedParties); equal(phaser.getArrivedParties(), arrivedParties);

View File

@ -0,0 +1,150 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/licenses/publicdomain
*/
/*
* @test
* @summary stress test for register/arriveAndDeregister
* @run main FickleRegister 300
*/
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class FickleRegister {
final AtomicLong count = new AtomicLong(0);
final long testDurationMillisDefault = 10L * 1000L;
final long testDurationMillis;
final long quittingTimeNanos;
final int chunkSize = 1000;
FickleRegister(String[] args) {
testDurationMillis = (args.length > 0) ?
Long.valueOf(args[0]) : testDurationMillisDefault;
quittingTimeNanos = System.nanoTime() +
testDurationMillis * 1000L * 1000L;
}
class Runner extends CheckedRunnable {
final Phaser p;
Runner(Phaser phaser) { p = phaser; }
public void realRun() {
int prevPhase = -1;
for (int k = 1;; k++) {
for (int i = 0; i < chunkSize; i++) {
int phase = p.register();
if (phase < 0) break;
check(phase > prevPhase);
prevPhase = phase;
equal(phase, p.arriveAndDeregister());
check(phase < p.awaitAdvance(phase));
}
if (System.nanoTime() - quittingTimeNanos > 0) {
count.getAndAdd(k * chunkSize);
break;
}
}
}
}
void test(String[] args) throws Throwable {
final Phaser parent = new Phaser() {
protected boolean onAdvance(int phase, int parties) {
return false;
}
};
final Phaser child1 = new Phaser(parent);
final Phaser child2 = new Phaser(parent);
final Phaser subchild1 = new Phaser(child1);
final Phaser subchild2 = new Phaser(child2);
final Phaser[] phasers = {
parent, child1, child2, subchild1, subchild2
};
int reps = 4;
ArrayList<Thread> threads = new ArrayList<Thread>();
for (int j = 0; j < reps; ++j) {
threads.add(new Thread(new Runner(subchild1)));
threads.add(new Thread(new Runner(child1)));
threads.add(new Thread(new Runner(parent)));
threads.add(new Thread(new Runner(child2)));
threads.add(new Thread(new Runner(subchild2)));
}
for (Thread thread : threads)
thread.start();
for (Thread thread : threads)
thread.join();
System.out.println("Parent: " + parent);
System.out.println("Child1: " + child1);
System.out.println("Child2: " + child2);
System.out.println("Subchild1: " + subchild1);
System.out.println("Subchild2: " + subchild2);
System.out.println("Iterations:" + count.get());
for (Phaser phaser : phasers) {
check(phaser.getPhase() > 0);
equal(0, phaser.getRegisteredParties());
equal(0, phaser.getUnarrivedParties());
equal(parent.getPhase(), phaser.getPhase());
}
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new FickleRegister(args).instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
abstract class CheckedRunnable implements Runnable {
protected abstract void realRun() throws Throwable;
public final void run() {
try {realRun();} catch (Throwable t) {unexpected(t);}
}
}
}

View File

@ -0,0 +1,158 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Martin Buchholz and Doug Lea with assistance from
* members of JCP JSR-166 Expert Group and released to the public
* domain, as explained at
* http://creativecommons.org/licenses/publicdomain
*/
/*
* @test
* @summary Test Phaser phase integer overflow behavior
*/
import java.util.concurrent.Phaser;
import java.lang.reflect.Field;
public class PhaseOverflow {
Field stateField;
void checkState(Phaser phaser,
int phase, int parties, int unarrived) {
equal(phase, phaser.getPhase());
equal(parties, phaser.getRegisteredParties());
equal(unarrived, phaser.getUnarrivedParties());
}
void test(String[] args) throws Throwable {
stateField = Phaser.class.getDeclaredField("state");
stateField.setAccessible(true);
testLeaf();
testTiered();
}
void testLeaf() throws Throwable {
Phaser phaser = new Phaser();
// this is extremely dependent on internal representation
stateField.setLong(phaser, ((Integer.MAX_VALUE - 1L) << 32) | 1L);
checkState(phaser, Integer.MAX_VALUE - 1, 0, 0);
phaser.register();
checkState(phaser, Integer.MAX_VALUE - 1, 1, 1);
phaser.arrive();
checkState(phaser, Integer.MAX_VALUE, 1, 1);
phaser.arrive();
checkState(phaser, 0, 1, 1);
phaser.arrive();
checkState(phaser, 1, 1, 1);
}
int phaseInc(int phase) { return (phase + 1) & Integer.MAX_VALUE; }
void testTiered() throws Throwable {
Phaser root = new Phaser();
// this is extremely dependent on internal representation
stateField.setLong(root, ((Integer.MAX_VALUE - 1L) << 32) | 1L);
checkState(root, Integer.MAX_VALUE - 1, 0, 0);
Phaser p1 = new Phaser(root, 1);
checkState(root, Integer.MAX_VALUE - 1, 1, 1);
checkState(p1, Integer.MAX_VALUE - 1, 1, 1);
Phaser p2 = new Phaser(root, 2);
checkState(root, Integer.MAX_VALUE - 1, 2, 2);
checkState(p2, Integer.MAX_VALUE - 1, 2, 2);
int ph = Integer.MAX_VALUE - 1;
for (int k = 0; k < 5; k++) {
checkState(root, ph, 2, 2);
checkState(p1, ph, 1, 1);
checkState(p2, ph, 2, 2);
p1.arrive();
checkState(root, ph, 2, 1);
checkState(p1, ph, 1, 0);
checkState(p2, ph, 2, 2);
p2.arrive();
checkState(root, ph, 2, 1);
checkState(p1, ph, 1, 0);
checkState(p2, ph, 2, 1);
p2.arrive();
ph = phaseInc(ph);
checkState(root, ph, 2, 2);
checkState(p1, ph, 1, 1);
checkState(p2, ph, 2, 2);
}
equal(3, ph);
}
void xtestTiered() throws Throwable {
Phaser root = new Phaser();
stateField.setLong(root, ((Integer.MAX_VALUE - 1L) << 32) | 1L);
checkState(root, Integer.MAX_VALUE - 1, 0, 0);
Phaser p1 = new Phaser(root, 1);
checkState(root, Integer.MAX_VALUE - 1, 1, 1);
checkState(p1, Integer.MAX_VALUE - 1, 1, 1);
Phaser p2 = new Phaser(root, 2);
checkState(root, Integer.MAX_VALUE - 1, 2, 2);
checkState(p2, Integer.MAX_VALUE - 1, 2, 2);
int ph = Integer.MAX_VALUE - 1;
for (int k = 0; k < 5; k++) {
checkState(root, ph, 2, 2);
checkState(p1, ph, 1, 1);
checkState(p2, ph, 2, 2);
p1.arrive();
checkState(root, ph, 2, 1);
checkState(p1, ph, 1, 0);
checkState(p2, ph, 2, 2);
p2.arrive();
checkState(root, ph, 2, 1);
checkState(p1, ph, 1, 0);
checkState(p2, ph, 2, 1);
p2.arrive();
ph = phaseInc(ph);
checkState(root, ph, 2, 2);
checkState(p1, ph, 1, 1);
checkState(p2, ph, 2, 2);
}
equal(3, ph);
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new PhaseOverflow().instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
}

View File

@ -0,0 +1,117 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/licenses/publicdomain
*/
/*
* @test
* @summary stress test for arrivals in a tiered phaser
* @run main TieredArriveLoops 300
*/
import java.util.*;
import java.util.concurrent.*;
public class TieredArriveLoops {
final long testDurationMillisDefault = 10L * 1000L;
final long testDurationMillis;
final long quittingTimeNanos;
TieredArriveLoops(String[] args) {
testDurationMillis = (args.length > 0) ?
Long.valueOf(args[0]) : testDurationMillisDefault;
quittingTimeNanos = System.nanoTime() +
testDurationMillis * 1000L * 1000L;
}
Runnable runner(final Phaser p) {
return new CheckedRunnable() { public void realRun() {
int prevPhase = p.register();
while (!p.isTerminated()) {
int phase = p.awaitAdvance(p.arrive());
if (phase < 0)
return;
equal(phase, (prevPhase + 1) & Integer.MAX_VALUE);
int ph = p.getPhase();
check(ph < 0 || ph == phase);
prevPhase = phase;
}
}};
}
void test(String[] args) throws Throwable {
final Phaser parent = new Phaser();
final Phaser child1 = new Phaser(parent);
final Phaser child2 = new Phaser(parent);
Thread t1 = new Thread(runner(child1));
Thread t2 = new Thread(runner(child2));
t1.start();
t2.start();
for (int prevPhase = 0, phase; ; prevPhase = phase) {
phase = child2.getPhase();
check(phase >= prevPhase);
if (System.nanoTime() - quittingTimeNanos > 0) {
System.err.printf("phase=%d%n", phase);
child1.forceTermination();
break;
}
}
t1.join();
t2.join();
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new TieredArriveLoops(args).instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
abstract class CheckedRunnable implements Runnable {
protected abstract void realRun() throws Throwable;
public final void run() {
try {realRun();} catch (Throwable t) {unexpected(t);}
}
}
}

View File

@ -31,47 +31,79 @@
import java.util.concurrent.*; import java.util.concurrent.*;
public class CoreThreadTimeOut { public class CoreThreadTimeOut {
static volatile int passed = 0, failed = 0;
static void pass() { passed++; }
static void fail() { failed++; Thread.dumpStack(); }
static void unexpected(Throwable t) { failed++; t.printStackTrace(); }
static void check(boolean cond) { if (cond) pass(); else fail(); }
static void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else {System.out.println(x + " not equal to " + y); fail(); }}
static int countExecutorThreads() { static class IdentifiableThreadFactory implements ThreadFactory {
static ThreadFactory defaultThreadFactory
= Executors.defaultThreadFactory();
public Thread newThread(Runnable r) {
Thread t = defaultThreadFactory.newThread(r);
t.setName("CoreThreadTimeOut-" + t.getName());
return t;
}
}
int countExecutorThreads() {
Thread[] threads = new Thread[Thread.activeCount()+100]; Thread[] threads = new Thread[Thread.activeCount()+100];
Thread.enumerate(threads); Thread.enumerate(threads);
int count = 0; int count = 0;
for (Thread t : threads) for (Thread t : threads)
if (t != null && t.getName().matches("pool-[0-9]+-thread-[0-9]+")) if (t != null &&
t.getName().matches
("CoreThreadTimeOut-pool-[0-9]+-thread-[0-9]+"))
count++; count++;
return count; return count;
} }
public static void main(String[] args) throws Throwable { long millisElapsedSince(long t0) {
return (System.nanoTime() - t0) / (1000L * 1000L);
}
void test(String[] args) throws Throwable {
final int threadCount = 10; final int threadCount = 10;
final int timeoutMillis = 30;
BlockingQueue<Runnable> q BlockingQueue<Runnable> q
= new ArrayBlockingQueue<Runnable>(2*threadCount); = new ArrayBlockingQueue<Runnable>(2*threadCount);
ThreadPoolExecutor tpe ThreadPoolExecutor tpe
= new ThreadPoolExecutor(threadCount, threadCount, = new ThreadPoolExecutor(threadCount, threadCount,
30, TimeUnit.MILLISECONDS, timeoutMillis, TimeUnit.MILLISECONDS,
q); q, new IdentifiableThreadFactory());
equal(tpe.getCorePoolSize(), threadCount); equal(tpe.getCorePoolSize(), threadCount);
check(! tpe.allowsCoreThreadTimeOut()); check(! tpe.allowsCoreThreadTimeOut());
tpe.allowCoreThreadTimeOut(true); tpe.allowCoreThreadTimeOut(true);
check(tpe.allowsCoreThreadTimeOut()); check(tpe.allowsCoreThreadTimeOut());
equal(countExecutorThreads(), 0); equal(countExecutorThreads(), 0);
long t0 = System.nanoTime();
for (int i = 0; i < threadCount; i++) for (int i = 0; i < threadCount; i++)
tpe.submit(new Runnable() { public void run() {}}); tpe.submit(new Runnable() { public void run() {}});
equal(countExecutorThreads(), threadCount); int count = countExecutorThreads();
Thread.sleep(500); if (millisElapsedSince(t0) < timeoutMillis)
equal(count, threadCount);
while (countExecutorThreads() > 0 &&
millisElapsedSince(t0) < 10 * 1000);
equal(countExecutorThreads(), 0); equal(countExecutorThreads(), 0);
tpe.shutdown(); tpe.shutdown();
check(tpe.allowsCoreThreadTimeOut()); check(tpe.allowsCoreThreadTimeOut());
check(tpe.awaitTermination(10, TimeUnit.SECONDS));
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new Exception("Some tests failed"); if (failed > 0) throw new Exception("Some tests failed");
} }
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.err.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new CoreThreadTimeOut().instanceMain(args);}
public void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
} }

View File

@ -78,8 +78,8 @@ public class IPv6 {
try { try {
Subject subject = new Subject(); Subject subject = new Subject();
Krb5LoginModule krb5 = new Krb5LoginModule(); Krb5LoginModule krb5 = new Krb5LoginModule();
Map<String, String> map = new HashMap<String, String>(); Map<String, String> map = new HashMap<>();
Map<String, Object> shared = new HashMap<String, Object>(); Map<String, Object> shared = new HashMap<>();
map.put("debug", "true"); map.put("debug", "true");
map.put("doNotPrompt", "true"); map.put("doNotPrompt", "true");

View File

@ -49,11 +49,11 @@ public class CleanState {
final char[] password = OneKDC.PASS; final char[] password = OneKDC.PASS;
char[] badpassword = "hellokitty".toCharArray(); char[] badpassword = "hellokitty".toCharArray();
Map<String,String> map = new HashMap<String,String>(); Map<String,String> map = new HashMap<>();
map.put("useTicketCache", "false"); map.put("useTicketCache", "false");
map.put("doNotPrompt", "false"); map.put("doNotPrompt", "false");
map.put("tryFirstPass", "true"); map.put("tryFirstPass", "true");
Map<String,Object> shared = new HashMap<String,Object>(); Map<String,Object> shared = new HashMap<>();
shared.put("javax.security.auth.login.name", name); shared.put("javax.security.auth.login.name", name);
shared.put("javax.security.auth.login.password", badpassword); shared.put("javax.security.auth.login.password", badpassword);

View File

@ -117,8 +117,8 @@ public class Context {
out.name = user; out.name = user;
out.s = new Subject(); out.s = new Subject();
Krb5LoginModule krb5 = new Krb5LoginModule(); Krb5LoginModule krb5 = new Krb5LoginModule();
Map<String, String> map = new HashMap<String, String>(); Map<String, String> map = new HashMap<>();
Map<String, Object> shared = new HashMap<String, Object>(); Map<String, Object> shared = new HashMap<>();
if (pass != null) { if (pass != null) {
map.put("useFirstPass", "true"); map.put("useFirstPass", "true");
@ -151,7 +151,7 @@ public class Context {
out.name = user; out.name = user;
out.s = new Subject(); out.s = new Subject();
Krb5LoginModule krb5 = new Krb5LoginModule(); Krb5LoginModule krb5 = new Krb5LoginModule();
Map<String, String> map = new HashMap<String, String>(); Map<String, String> map = new HashMap<>();
map.put("doNotPrompt", "true"); map.put("doNotPrompt", "true");
map.put("useTicketCache", "false"); map.put("useTicketCache", "false");

View File

@ -297,8 +297,8 @@ public class HttpNegotiateServer {
} }
Krb5LoginModule krb5 = new Krb5LoginModule(); Krb5LoginModule krb5 = new Krb5LoginModule();
Map<String, String> map = new HashMap<String, String>(); Map<String, String> map = new HashMap<>();
Map<String, Object> shared = new HashMap<String, Object>(); Map<String, Object> shared = new HashMap<>();
map.put("storeKey", "true"); map.put("storeKey", "true");
map.put("isInitiator", "false"); map.put("isInitiator", "false");

View File

@ -132,7 +132,7 @@ public class KDC {
// Principal db. principal -> pass. A case-insensitive TreeMap is used // Principal db. principal -> pass. A case-insensitive TreeMap is used
// so that even if the client provides a name with different case, the KDC // so that even if the client provides a name with different case, the KDC
// can still locate the principal and give back correct salt. // can still locate the principal and give back correct salt.
private TreeMap<String,char[]> passwords = new TreeMap<String,char[]> private TreeMap<String,char[]> passwords = new TreeMap<>
(String.CASE_INSENSITIVE_ORDER); (String.CASE_INSENSITIVE_ORDER);
// Realm name // Realm name
@ -142,9 +142,9 @@ public class KDC {
// Service port number // Service port number
private int port; private int port;
// The request/response job queue // The request/response job queue
private BlockingQueue<Job> q = new ArrayBlockingQueue<Job>(100); private BlockingQueue<Job> q = new ArrayBlockingQueue<>(100);
// Options // Options
private Map<Option,Object> options = new HashMap<Option,Object>(); private Map<Option,Object> options = new HashMap<>();
private Thread thread1, thread2, thread3; private Thread thread1, thread2, thread3;
DatagramSocket u1 = null; DatagramSocket u1 = null;
@ -537,7 +537,7 @@ public class KDC {
} }
} }
private Map<String,String> policies = new HashMap<String,String>(); private Map<String,String> policies = new HashMap<>();
public void setPolicy(String rule, String value) { public void setPolicy(String rule, String value) {
if (value == null) { if (value == null) {
@ -760,7 +760,7 @@ public class KDC {
private byte[] processAsReq(byte[] in) throws Exception { private byte[] processAsReq(byte[] in) throws Exception {
ASReq asReq = new ASReq(in); ASReq asReq = new ASReq(in);
int[] eTypes = null; int[] eTypes = null;
List<PAData> outPAs = new ArrayList<PAData>(); List<PAData> outPAs = new ArrayList<>();
try { try {
System.out.println(realm + "> " + asReq.reqBody.cname + System.out.println(realm + "> " + asReq.reqBody.cname +

View File

@ -135,8 +135,8 @@ public class LoginModuleOptions {
throws Exception { throws Exception {
Krb5LoginModule krb5 = new Krb5LoginModule(); Krb5LoginModule krb5 = new Krb5LoginModule();
Subject subject = new Subject(); Subject subject = new Subject();
Map<String, String> map = new HashMap<String, String>(); Map<String, String> map = new HashMap<>();
Map<String, Object> shared = new HashMap<String, Object>(); Map<String, Object> shared = new HashMap<>();
int count = options.length / 2; int count = options.length / 2;
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {

View File

@ -39,7 +39,7 @@ public class KtabCheck {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
System.out.println("Checking " + Arrays.toString(args)); System.out.println("Checking " + Arrays.toString(args));
KeyTab ktab = KeyTab.getInstance(args[0]); KeyTab ktab = KeyTab.getInstance(args[0]);
Set<String> expected = new HashSet<String>(); Set<String> expected = new HashSet<>();
for (int i=1; i<args.length; i += 2) { for (int i=1; i<args.length; i += 2) {
expected.add(args[i]+":"+args[i+1]); expected.add(args[i]+":"+args[i+1]);
} }