Skip to content

Commit

Permalink
Merge tag '1.5.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
yongjhih committed Mar 21, 2017
2 parents 502a8cc + c2f02b5 commit ac28178
Show file tree
Hide file tree
Showing 74 changed files with 7,691 additions and 2,133 deletions.
58 changes: 58 additions & 0 deletions Known_Problems.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@

KNOWN PROBLEMS
--------------

- Incorrect LinkedHashMap Spliterator ordering in Android N.

The implementation of LinkedHashMap's collection views' spliterators in
Android Nougat (API levels 24 and 25) uses the wrong order (inconsistent
with the iterators, which use the correct order), despite reporting
Spliterator#ORDERED (however, the unordered HashMap spliterators are used).

Since streamsupport 1.5.3 and later will by default delegate to the Android 7.x
spliterators you'd be affected by this unordered behavior on Android 7.x unless
you disable spliterator delegation altogether or you workaround this behavior
on API level 24 and 25 as follows.

You may use the following code to obtain a correctly ordered Spliterator:

For a Collection view
col = lhm.keySet(), col = lhm.entrySet() or col = lhm.values(), use

Spliterator sp = java8.util.Spliterators.spliterator(col, c) where

int c = Spliterator.DISTINCT | Spliterator.ORDERED | Spliterator.SIZED

for keySet() and entrySet() and

int c = Spliterator.ORDERED | Spliterator.SIZED for values()

to obtain a correctly ordered spliterator. Then, instead of
StreamSupport.stream(col) or StreamSupport.parallelStream(col), use

java8.util.stream.StreamSupport.stream(sp, false)

to construct a (nonparallel) java8.util.stream.Stream from the Spliterator sp.

Note that these workarounds are only suggested where lhm is a LinkedHashMap.
Note further that everything works perfectly fine on API level 23 and below (if
you don't plan to deploy on Android 7.x devices, you can ignore this whole advice
altogether).

To mitigate the risk if you don't follow this advice, streamsupport 1.5.3 (and
later) exercises a check whether the spliterator for a HashMap collection view
reports ORDERED (a bug) and excepts these cases from the delegation mechanism
(using the reflective implementation instead. So, in effect the same mechanism
that is used on API level 23 and below gets employed in this case).

But note that this check isn't 100% fool-proof as the LinkedHashMap (or its
collection view) could be wrapped, for example in a j.u.Collections$UnmodifiableMap
(whose UnmodifiableEntrySetSpliterator delegates back to the defective
HashMap$EntrySpliterator).

Since we can't know an arbitrary wrapper beforehand there is nothing streamsupport
can do about this in such cases - you have been warned.

The latest version of LinkedHashMap in AOSP implements its Spliterators via
Spliterators.spliterator(), which means that this bug has already been fixed
in Android O.
503 changes: 503 additions & 0 deletions Readme.txt

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>net.sourceforge.streamsupport</groupId>
<artifactId>streamsupport</artifactId>
<version>1.5.3</version>
<version>1.5.4</version>
<name>net.sourceforge.streamsupport:streamsupport</name>
<description>streamsupport is a backport of the Java 8 java.util.function (functional interfaces) and
java.util.stream (streams) API for Java 6 / 7 and Android developers</description>
Expand Down Expand Up @@ -54,7 +54,7 @@
</execution>
</executions>
<configuration>
<java8home>F:/Java/jdk1.8.0_112-64bit/</java8home>
<java8home>F:/Java/jdk1.8.0_121-64bit/</java8home>
<target>1.6</target>
</configuration>
</plugin>
Expand Down Expand Up @@ -130,7 +130,7 @@ unction;java8.util.stream</Export-Package>
<version>1.1</version>
</signature>
<annotations>
<annotation>build.IgnoreJava8API</annotation>
<annotation>build.IgnoreJava8API</annotation>
</annotations>
<ignores>
<ignore>sun.misc.Unsafe</ignore>
Expand Down
2,875 changes: 1,303 additions & 1,572 deletions src/alternative/java/java8/util/concurrent/ForkJoinPool.java

Large diffs are not rendered by default.

203 changes: 203 additions & 0 deletions src/alternative/java/java8/util/concurrent/ForkJoinWorkerThread.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
/*
* 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/publicdomain/zero/1.0/
*/
package java8.util.concurrent;

import java.security.AccessControlContext;
import java.security.ProtectionDomain;

/**
* A thread managed by a {@link ForkJoinPool}, which executes
* {@link ForkJoinTask}s.
* This class is subclassable solely for the sake of adding
* functionality -- there are no overridable methods dealing with
* scheduling or execution. However, you can override initialization
* and termination methods surrounding the main task processing loop.
* If you do create such a subclass, you will also need to supply a
* custom {@link ForkJoinPool.ForkJoinWorkerThreadFactory} to
* {@linkplain ForkJoinPool#ForkJoinPool use it} in a {@code ForkJoinPool}.
*
* @since 1.7
* @author Doug Lea
*/
public class ForkJoinWorkerThread extends Thread {
// CVS rev. 1.73
/*
* ForkJoinWorkerThreads are managed by ForkJoinPools and perform
* ForkJoinTasks. For explanation, see the internal documentation
* of class ForkJoinPool.
*
* This class just maintains links to its pool and WorkQueue. The
* pool field is set immediately upon construction, but the
* workQueue field is not set until a call to registerWorker
* completes. This leads to a visibility race, that is tolerated
* by requiring that the workQueue field is only accessed by the
* owning thread.
*
* Support for (non-public) subclass InnocuousForkJoinWorkerThread
* requires that we break quite a lot of encapsulation (via helper
* methods in ThreadLocalRandom) both here and in the subclass to
* access and set Thread fields.
*/

// A placeholder name until a useful name can be set in registerWorker
private static final String NAME_PLACEHOLDER = "aForkJoinWorkerThread";

final ForkJoinPool pool; // the pool this thread works in
final ForkJoinPool.WorkQueue workQueue; // work-stealing mechanics

/**
* Creates a ForkJoinWorkerThread operating in the given pool.
*
* @param pool the pool this thread works in
* @throws NullPointerException if pool is null
*/
protected ForkJoinWorkerThread(ForkJoinPool pool) {
// Use a placeholder until a useful name can be set in registerWorker
super(NAME_PLACEHOLDER);
this.pool = pool;
this.workQueue = pool.registerWorker(this);
}

// note that this will never get called on Android
/**
* Version for InnocuousForkJoinWorkerThread.
*/
ForkJoinWorkerThread(ForkJoinPool pool, ThreadGroup threadGroup,
AccessControlContext acc) {
super(threadGroup, NAME_PLACEHOLDER);
TLRandom.setInheritedAccessControlContext(this, acc);
TLRandom.eraseThreadLocals(this); // clear before registering
this.pool = pool;
this.workQueue = pool.registerWorker(this);
}

/**
* Returns the pool hosting this thread.
*
* @return the pool
*/
public ForkJoinPool getPool() {
return pool;
}

/**
* Returns the unique index number of this thread in its pool.
* The returned value ranges from zero to the maximum number of
* threads (minus one) that may exist in the pool, and does not
* change during the lifetime of the thread. This method may be
* useful for applications that track status or collect results
* per-worker-thread rather than per-task.
*
* @return the index number
*/
public int getPoolIndex() {
return workQueue.getPoolIndex();
}

/**
* Initializes internal state after construction but before
* processing any tasks. If you override this method, you must
* invoke {@code super.onStart()} at the beginning of the method.
* Initialization requires care: Most fields must have legal
* default values, to ensure that attempted accesses from other
* threads work correctly even before this thread starts
* processing tasks.
*/
protected void onStart() {
}

/**
* Performs cleanup associated with termination of this worker
* thread. If you override this method, you must invoke
* {@code super.onTermination} at the end of the overridden method.
*
* @param exception the exception causing this thread to abort due
* to an unrecoverable error, or {@code null} if completed normally
*/
protected void onTermination(Throwable exception) {
}

/**
* This method is required to be public, but should never be
* called explicitly. It performs the main run loop to execute
* {@link ForkJoinTask}s.
*/
public void run() {
if (workQueue.array == null) { // only run once
Throwable exception = null;
try {
onStart();
pool.runWorker(workQueue);
} catch (Throwable ex) {
exception = ex;
} finally {
try {
onTermination(exception);
} catch (Throwable ex) {
if (exception == null) {
exception = ex;
}
} finally {
pool.deregisterWorker(this, exception);
}
}
}
}

/**
* Non-public hook method for InnocuousForkJoinWorkerThread.
*/
void afterTopLevelExec() {
}

// note that this will never get called on Android!
/**
* A worker thread that has no permissions, is not a member of any
* user-defined ThreadGroup, and erases all ThreadLocals after
* running each top-level task.
*/
static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
/** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
private static final ThreadGroup innocuousThreadGroup =
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<ThreadGroup>() {
public ThreadGroup run() {
ThreadGroup group = Thread.currentThread().getThreadGroup();
for (ThreadGroup p; (p = group.getParent()) != null; )
group = p;
return new ThreadGroup(group, "InnocuousForkJoinWorkerThreadGroup");
}});

/** An AccessControlContext supporting no privileges */
private static final AccessControlContext INNOCUOUS_ACC =
new AccessControlContext(
new ProtectionDomain[] {
new ProtectionDomain(null, null)
});

InnocuousForkJoinWorkerThread(ForkJoinPool pool) {
super(pool, innocuousThreadGroup, INNOCUOUS_ACC);
}

@Override // to erase ThreadLocals
void afterTopLevelExec() {
TLRandom.eraseThreadLocals(this);
}

@Override // to always report system loader
public ClassLoader getContextClassLoader() {
return ClassLoader.getSystemClassLoader();
}

@Override // to silently fail
public void setUncaughtExceptionHandler(UncaughtExceptionHandler x) { }

@Override // paranoically
public void setContextClassLoader(ClassLoader cl) {
throw new SecurityException("setContextClassLoader");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/
@SuppressWarnings("serial")
abstract class Striped64 extends Number {
// CVS rev. 1.21
// CVS rev. 1.22
/*
* This class maintains a lazily-initialized table of atomically
* updated variables, plus an extra "base" field. The table size
Expand Down
4 changes: 2 additions & 2 deletions src/atomic/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>net.sourceforge.streamsupport</groupId>
<artifactId>streamsupport-atomic</artifactId>
<version>1.5.3</version>
<version>1.5.4</version>
<name>net.sourceforge.streamsupport:streamsupport-atomic</name>
<description>streamsupport-atomic is a backport of the java.util.concurrent.atomic classes
added in Java 8 (Double/Long Accumulator/Adder) for Java 6 / 7 and Android developers</description>
Expand Down Expand Up @@ -32,7 +32,7 @@
<dependency>
<groupId>net.sourceforge.streamsupport</groupId>
<artifactId>streamsupport</artifactId>
<version>1.5.3</version>
<version>1.5.4</version>
</dependency>
</dependencies>
<properties>
Expand Down
4 changes: 2 additions & 2 deletions src/cfuture/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>net.sourceforge.streamsupport</groupId>
<artifactId>streamsupport-cfuture</artifactId>
<version>1.5.3</version>
<version>1.5.4</version>
<name>net.sourceforge.streamsupport:streamsupport-cfuture</name>
<description>streamsupport-cfuture is a backport of the Java 8 CompletableFuture API with the current
Java 9 (JEP 266) enhancements for Java 6 to 8 and Android developers</description>
Expand Down Expand Up @@ -32,7 +32,7 @@
<dependency>
<groupId>net.sourceforge.streamsupport</groupId>
<artifactId>streamsupport</artifactId>
<version>1.5.3</version>
<version>1.5.4</version>
</dependency>
</dependencies>
<properties>
Expand Down
12 changes: 6 additions & 6 deletions src/flow/java/java8/util/concurrent/Flow.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@
* @since 9
*/
public final class Flow {
// CVS rev. 1.30
// CVS rev. 1.31
private Flow() {} // uninstantiable

/**
Expand Down Expand Up @@ -243,11 +243,11 @@ public static interface Subscription {
/**
* Adds the given number {@code n} of items to the current
* unfulfilled demand for this subscription. If {@code n} is
* negative, the Subscriber will receive an {@code onError}
* signal with an {@link IllegalArgumentException} argument.
* Otherwise, the Subscriber will receive up to {@code n}
* additional {@code onNext} invocations (or fewer if
* terminated).
* less than or equal to zero, the Subscriber will receive an
* {@code onError} signal with an {@link
* IllegalArgumentException} argument. Otherwise, the
* Subscriber will receive up to {@code n} additional {@code
* onNext} invocations (or fewer if terminated).
*
* @param n the increment of demand; a value of {@code
* Long.MAX_VALUE} may be considered as effectively unbounded
Expand Down

0 comments on commit ac28178

Please sign in to comment.