Author: desruisseaux
Date: Sun Jan 6 16:08:55 2013
New Revision: 1429547
URL: http://svn.apache.org/viewvc?rev=1429547&view=rev
Log:
Replaced the ThreadPoolExecutor by a more lightweight approach for the SIS
needs (SIS-76).
Added:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DelayedExecutor.java
- copied, changed from r1427508,
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/ReferenceQueueConsumer.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DelayedRunnable.java
(with props)
Removed:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Executors.java
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DaemonThread.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/ReferenceQueueConsumer.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Threads.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/WeakEntry.java
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/collection/CacheTest.java
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DaemonThread.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DaemonThread.java?rev=1429547&r1=1429546&r2=1429547&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DaemonThread.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DaemonThread.java
Sun Jan 6 16:08:55 2013
@@ -47,9 +47,8 @@ abstract class DaemonThread extends Thre
/**
* The previous element in a chain of {@code DaemonThread}s. We maintain a
linked list of
* {@code DaemonThread} to be killed when {@link #killAll(DaemonThread)}
will be invoked.
- * We do not rely on the thread listed by the {@link
Threads#RESOURCE_DISPOSERS} group
- * because in an OSGi context, we need to handle separately the threads
created by each
- * SIS module.
+ * We do not rely on the thread listed by the {@link Threads#DAEMONS}
group because in an
+ * OSGi context, we need to handle separately the threads created by each
SIS module.
*/
private final DaemonThread previous;
@@ -76,20 +75,19 @@ abstract class DaemonThread extends Thre
* static {
* synchronized (MyInternalClass.class) {
* MyInternalClass.lastCreatedDaemon = myDaemonThread =
new MyDaemonThread(
- * Threads.RESOURCE_DISPOSERS, "MyThread",
MyInternalClass.lastCreatedDaemon);
+ * "MyThread", MyInternalClass.lastCreatedDaemon);
* }
* }
* }
*
* See {@link ReferenceQueueConsumer} for a real example.
*
- * @param group The thread group.
- * @param name The thread name.
+ * @param name The thread name.
* @param lastCreatedDaemon The previous element in a chain of {@code
DaemonThread}s,
* or {@code null}. Each SIS module shall maintain its own chain,
if any.
*/
- protected DaemonThread(final ThreadGroup group, final String name, final
DaemonThread lastCreatedDaemon) {
- super(group, name);
+ protected DaemonThread(final String name, final DaemonThread
lastCreatedDaemon) {
+ super(Threads.DAEMONS, name);
previous = lastCreatedDaemon;
setDaemon(true);
}
Copied:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DelayedExecutor.java
(from r1427508,
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/ReferenceQueueConsumer.java)
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DelayedExecutor.java?p2=sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DelayedExecutor.java&p1=sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/ReferenceQueueConsumer.java&r1=1427508&r2=1429547&rev=1429547&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/ReferenceQueueConsumer.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DelayedExecutor.java
Sun Jan 6 16:08:55 2013
@@ -16,79 +16,138 @@
*/
package org.apache.sis.internal.util;
-import java.lang.ref.Reference;
-import java.lang.ref.ReferenceQueue;
-
-import org.apache.sis.util.Disposable;
+import java.util.concurrent.DelayQueue;
+import java.util.concurrent.BlockingQueue;
import org.apache.sis.util.logging.Logging;
/**
- * A thread processing all {@link Reference} instances enqueued in a {@link
ReferenceQueue}.
- * This is the central place where <em>every</em> weak references produced by
the SIS library
- * are consumed. This thread will invoke the {@link Disposeable#dispose()}
method for each
- * references enqueued by the garbage collector. Those references
<strong>must</strong>
- * implement the {@link Disposable} interface.
- *
- * Example:
- *
- * {@preformat java
- * final class MyReference extends WeakReference<MyType> implements
Disposable {
- * MyReference(MyType referent) {
- * super(referent, ReferenceQueueConsumer.DEFAULT.queue);
- * assert ReferenceQueueConsumer.DEFAULT.isAlive();
- * }
- *
- * @Override
- * public void dispose() {
- * // Perform here some cleaning work that must be done when the
referent has
- * // been garbage-collected. Remember that get() returns null
from this point.
- * }
- * }
- * }
+ * A thread executing short tasks after some (potentially zero nanosecond)
delay.
+ * This thread is reserved to internal SIS usage - no user code shall be
executed here.
+ * All submitted tasks shall be very quick, since there is only one thread
shared by everyone.
+ *
+ * {@note In practice some user code may be indirectly executed, since some
SIS tasks invoke
+ * overrideable methods. We may need to revisit the
<code>DelayedExecutor</code> design in a
+ * future version if the above happens to be a problem. For example we may
allow the user to
+ * specify an application-wide scheduled executor and delegate the tasks to
that executor.}
+ *
+ * The methods for use in this class are:
+ * <ul>
+ * <li>{@link #executeDaemonTask(DelayedRunnable)}</li>
+ * <li>{@link #schedule(DelayedRunnable)}</li>
+ * </ul>
*
- * @param <T> The type of objects being referenced.
+ * {@section Comparison with <code>java.util.concurrent</code>}
+ * We tried to use {@link java.util.concurrent.ScheduledThreadPoolExecutor} in
a previous version,
+ * but it seems more suitable to heavier tasks in applications controlling
their own executor. For
+ * example {@code ScheduledThreadPoolExecutor} acts as a fixed-sized pool,
thus forcing us to use
+ * only one thread if we don't want to waste resources (profiling shows that
even a single thread
+ * has very low activity). The {@code ThreadPoolExecutor} super-class is more
flexible but still
+ * have a quite aggressive policy on threads creation, and doesn't handle
delayed tasks by itself.
+ * We could combine both worlds with a {@code ThreadPoolExecutor} using a
{@code DelayedQueue},
+ * but it forces us to declare a core pool size of 0 otherwise {@code
ThreadPoolExecutor} tries
+ * to execute the tasks immediately without queuing them. Combined with the
{@code DelayedQueue}
+ * characteristics (being an unbounded queue), this result in {@code
ThreadPoolExecutor} never
+ * creating more than one thread (because it waits for the queue to reject a
task before to create
+ * more threads than the pool size).
+ *
+ * <p>Given that it seems difficult to configure {@code
(Scheduled)ThreadPoolExecutor} in such
+ * a way that two or more threads are created only when really needed, given
that using those
+ * thread pools seems an overkill when the pool size is fixed to one thread,
given that our
+ * profiling has show very low activity for that single thread anyway, and
given that we do
+ * not need cancellation and shutdown services for house keeping tasks (this
is a daemon thread),
+ * a more lightweight solution seems acceptable here. Pseudo-benchmarking
using the
+ * {@code CacheTest.stress()} tests suggests that the lightweight solution is
faster.</p>
+ *
+ * {@section Future evolution}
+ * We may remove (again) this class in a future SIS evolution if we happen to
need an executor anyway.
+ * However it may be better to wait and see what are the executor needs.
Setting up an executor implies
+ * choosing many arbitrary parameter values like the number of core threads,
maximum threads, idle time,
+ * queue capacity, etc. Furthermore some platforms (e.g. MacOS) provide
OS-specific implementations
+ * integrating well in their environment. We may want to let the user provides
the executor of his
+ * choice, or we way want to have more profiling data for choosing an
appropriate executor. But we
+ * may need to find some way to give priority to SIS tasks, since most of them
are for releasing
+ * resources - in which case quick execution probably help the system to run
faster.
+ * However before to switch from the lightweight solution to a more heavy
solution,
+ * micro-benchmarking is desirable. The {@code CacheTest.stress()} tests can
be used
+ * in first approximation.
*
* @author Martin Desruisseaux (Geomatys)
- * @since 0.3 (derived from geotk-3.00)
+ * @since 0.3
* @version 0.3
* @module
+ *
+ * @see <a href="https://issues.apache.org/jira/browse/SIS-76">SIS-76</a>
*/
-public final class ReferenceQueueConsumer<T> extends DaemonThread {
+public final class DelayedExecutor extends DaemonThread {
+ /**
+ * Executes the given short task in a daemon thread. This method shall be
invoked for
+ * Apache SIS tasks only, <strong>not</strong> for arbitrary user task.
The task must
+ * completes quickly, because we will typically use only one thread for
all submitted
+ * tasks. Completion of the task shall not be critical, since the JVM is
allowed to
+ * shutdown before task completion.
+ *
+ * {@section Future evolution}
+ * If {@code DelayedExecutor} is removed in a future SIS version in favor
of JDK6 executors,
+ * then the method signature will probably be {@code
Executors.execute(Runnable)}.
+ *
+ * @param task The task to execute.
+ */
+ public static void executeDaemonTask(final DelayedRunnable task) {
+ QUEUE.add(task);
+ }
+
/**
- * The singleton instance of the {@code ReferenceQueueConsumer} thread.
+ * Schedules the given short task for later execution in a daemon thread.
+ * The task will be executed after the delay specified by {@link
DelayedRunnable#getDelay}
+ * The task must completes quickly, because we will typically use only one
thread for all
+ * submitted tasks. Completion of the task shall not be critical, since
the JVM is allowed
+ * to shutdown before task completion.
+ *
+ * {@section Future evolution}
+ * If {@code DelayedExecutor} is removed in a future SIS version in favor
of JDK6 executors,
+ * then the method signature will probably be {@code
Executors.schedule(Runnable, long, TimeUnit)}.
+ *
+ * @param task The task to schedule for later execution.
+ */
+ public static void schedule(final DelayedRunnable task) {
+ // For now the implementation is identical to 'execute'. However it
may become
+ // different if we choose to use a library-wide executor in a future
SIS version.
+ QUEUE.add(task);
+ }
+
+ /**
+ * List of delayed tasks to execute.
+ */
+ private static final BlockingQueue<DelayedRunnable> QUEUE = new
DelayQueue<>();
+
+ /**
+ * Creates the singleton instance of the {@code DelayedExecutor} thread.
*/
- public static final ReferenceQueueConsumer<Object> DEFAULT;
static {
synchronized (Threads.class) {
- Threads.lastCreatedDaemon = DEFAULT = new
ReferenceQueueConsumer<>(Threads.lastCreatedDaemon);
+ final DelayedExecutor thread;
+ Threads.lastCreatedDaemon = thread = new
DelayedExecutor(Threads.lastCreatedDaemon);
+ // Call to Thread.start() must be outside the constructor
+ // (Reference: Goetz et al.: "Java Concurrency in Practice").
+ thread.start();
}
if (Supervisor.ENABLED) {
Supervisor.register();
}
- // Call to Thread.start() must be outside the constructor
- // (Reference: Goetz et al.: "Java Concurrency in Practice").
- DEFAULT.start();
}
/**
- * List of references collected by the garbage collector. This reference
shall be given to
- * {@link Reference} constructors as documented in the class javadoc.
Those {@code Reference}
- * sub-classes <strong>must</strong> implement the {@link Disposable}
interface.
- */
- public final ReferenceQueue<T> queue = new ReferenceQueue<>();
-
- /**
* Constructs a new thread as a daemon thread. This thread will be
sleeping most of the time.
- * It will run only only a few nanoseconds every time a new {@link
Reference} is enqueued.
+ * It will run only only a few nanoseconds every time a new {@link
DelayedRunnable} is taken.
*
* {@note We give to this thread a priority higher than the normal one
since this thread shall
* execute only tasks to be completed very shortly. Quick execution
of those tasks is at
* the benefit of the rest of the system, since they make more
resources available sooner.}
*/
- private ReferenceQueueConsumer(final DaemonThread lastCreatedDaemon) {
- super(Threads.DAEMONS, "ReferenceQueueConsumer", lastCreatedDaemon);
- setPriority(Thread.MAX_PRIORITY - 2);
+ private DelayedExecutor(final DaemonThread lastCreatedDaemon) {
+ super("DelayedExecutor", lastCreatedDaemon);
+ setPriority(Thread.NORM_PRIORITY + 1);
}
/**
@@ -102,24 +161,12 @@ public final class ReferenceQueueConsume
* observed at shutdown time. If the field become null, assume that a
shutdown is
* under way and let the thread terminate.
*/
- ReferenceQueue<T> queue;
- while ((queue = this.queue) != null) {
+ BlockingQueue<DelayedRunnable> queue;
+ while ((queue = QUEUE) != null) {
try {
- /*
- * Block until a reference is enqueued. The reference should
never be null
- * when using the method without timeout (it could be null if
we specified
- * a timeout). If the remove() method behaves as if a timeout
occurred, we
- * may be in the middle of a shutdown. Continue anyway as long
as we didn't
- * received the kill event.
- */
- final Reference<? extends T> ref = queue.remove();
- if (ref != null) {
- /*
- * If the reference does not implement the Disposeable
interface, we want
- * the ClassCastException to be logged in the "catch"
block since it would
- * be a programming error that we want to know about.
- */
- ((Disposable) ref).dispose();
+ final DelayedRunnable task = queue.take();
+ if (task != null) {
+ task.run();
continue;
}
} catch (InterruptedException exception) {
@@ -129,6 +176,7 @@ public final class ReferenceQueueConsume
Logging.unexpectedException(getClass(), "run", exception);
}
if (isKillRequested()) {
+ queue.clear();
break;
}
}
Added:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DelayedRunnable.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DelayedRunnable.java?rev=1429547&view=auto
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DelayedRunnable.java
(added)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DelayedRunnable.java
Sun Jan 6 16:08:55 2013
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.util;
+
+import java.util.concurrent.Delayed;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+import org.apache.sis.math.MathFunctions;
+
+
+/**
+ * A task to be submitted to {@link DelayedExecutor} for later execution.
+ *
+ * {@section Future evolution}
+ * This interface may be removed in a future SIS version if we choose to use a
library-wide executor
+ * instead of {@code DelayedExecutor}. See <a
href="https://issues.apache.org/jira/browse/SIS-76">SIS-76</a>
+ * for more information.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3
+ * @version 0.3
+ * @module
+ */
+public abstract class DelayedRunnable implements Delayed, Runnable {
+ /**
+ * Time of execution of this task, in nanoseconds provided by {@link
System#nanoTime()}.
+ * In the particular case of the {@link Immediate} subclass, the meaning
of this field is
+ * modified: it is rather an ordinal value used for preserving task order.
+ */
+ final long timestamp;
+
+ /**
+ * Creates a new task to be executed at the given time.
+ * It is user's responsibility to add the {@link System#nanoTime()} value
+ * to the delay he wants to wait.
+ *
+ * @param timestamp Time of execution of this task, in nanoseconds
relative to {@link System#nanoTime()}.
+ */
+ protected DelayedRunnable(final long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ /**
+ * Returns the delay to wait before to execute this task,
+ * or {@code 0} if this task shall be executed immediately.
+ */
+ @Override
+ public long getDelay(final TimeUnit unit) {
+ return unit.convert(timestamp - System.nanoTime(),
TimeUnit.NANOSECONDS);
+ }
+
+ /**
+ * Compares this task with the given delayed object for ordering.
+ * The {@code other} object shall be an instance of {@link
DelayedRunnable}.
+ * This restriction should be okay since the {@link DelayedExecutor} queue
+ * accepts only {@code DelayedRunnable} instances.
+ *
+ * @param other The other delayed object to compare with this delayed task.
+ */
+ @Override
+ public int compareTo(final Delayed other) {
+ if (other instanceof Immediate) {
+ return +1; // "Immediate" tasks always have precedence over
delayed ones.
+ }
+ return MathFunctions.sgn(timestamp - ((DelayedRunnable)
other).timestamp);
+ }
+
+ /**
+ * A "delayed" task which is actually executed as soon as possible.
+ * The delay is fixed to 0 seconds, however those tasks are still
+ * ordered in a "first created, first executed" basis.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3
+ * @version 0.3
+ * @module
+ */
+ public static abstract class Immediate extends DelayedRunnable {
+ /**
+ * A counter for ordering the tasks in a "first created, first
executed" basis.
+ */
+ private static final AtomicLong COUNTER = new
AtomicLong(Long.MIN_VALUE);
+
+ /**
+ * Creates a new immediate task.
+ */
+ protected Immediate() {
+ super(COUNTER.getAndIncrement());
+ }
+
+ /**
+ * Returns the delay, which is fixed to 0 in every cases.
+ */
+ @Override
+ public final long getDelay(final TimeUnit unit) {
+ return 0L;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final int compareTo(final Delayed other) {
+ if (other instanceof Immediate) {
+ if (timestamp > ((Immediate) other).timestamp) return +1;
+ // Should never be equal.
+ }
+ return -1;
+ }
+ }
+}
Propchange:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DelayedRunnable.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/DelayedRunnable.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/ReferenceQueueConsumer.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/ReferenceQueueConsumer.java?rev=1429547&r1=1429546&r2=1429547&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/ReferenceQueueConsumer.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/ReferenceQueueConsumer.java
Sun Jan 6 16:08:55 2013
@@ -18,7 +18,6 @@ package org.apache.sis.internal.util;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
-
import org.apache.sis.util.Disposable;
import org.apache.sis.util.logging.Logging;
@@ -35,8 +34,7 @@ import org.apache.sis.util.logging.Loggi
* {@preformat java
* final class MyReference extends WeakReference<MyType> implements
Disposable {
* MyReference(MyType referent) {
- * super(referent, ReferenceQueueConsumer.DEFAULT.queue);
- * assert ReferenceQueueConsumer.DEFAULT.isAlive();
+ * super(referent, ReferenceQueueConsumer.QUEUE);
* }
*
* @Override
@@ -47,38 +45,36 @@ import org.apache.sis.util.logging.Loggi
* }
* }
*
- * @param <T> The type of objects being referenced.
- *
* @author Martin Desruisseaux (Geomatys)
* @since 0.3 (derived from geotk-3.00)
* @version 0.3
* @module
*/
-public final class ReferenceQueueConsumer<T> extends DaemonThread {
+public final class ReferenceQueueConsumer extends DaemonThread {
+ /**
+ * List of references collected by the garbage collector. This reference
shall be given to
+ * {@link Reference} constructors as documented in the class javadoc.
Those {@code Reference}
+ * sub-classes <strong>must</strong> implement the {@link Disposable}
interface.
+ */
+ public static final ReferenceQueue<Object> QUEUE = new ReferenceQueue<>();
+
/**
- * The singleton instance of the {@code ReferenceQueueConsumer} thread.
+ * Creates the singleton instance of the {@code ReferenceQueueConsumer}
thread.
*/
- public static final ReferenceQueueConsumer<Object> DEFAULT;
static {
synchronized (Threads.class) {
- Threads.lastCreatedDaemon = DEFAULT = new
ReferenceQueueConsumer<>(Threads.lastCreatedDaemon);
+ final ReferenceQueueConsumer thread;
+ Threads.lastCreatedDaemon = thread = new
ReferenceQueueConsumer(Threads.lastCreatedDaemon);
+ // Call to Thread.start() must be outside the constructor
+ // (Reference: Goetz et al.: "Java Concurrency in Practice").
+ thread.start();
}
if (Supervisor.ENABLED) {
Supervisor.register();
}
- // Call to Thread.start() must be outside the constructor
- // (Reference: Goetz et al.: "Java Concurrency in Practice").
- DEFAULT.start();
}
/**
- * List of references collected by the garbage collector. This reference
shall be given to
- * {@link Reference} constructors as documented in the class javadoc.
Those {@code Reference}
- * sub-classes <strong>must</strong> implement the {@link Disposable}
interface.
- */
- public final ReferenceQueue<T> queue = new ReferenceQueue<>();
-
- /**
* Constructs a new thread as a daemon thread. This thread will be
sleeping most of the time.
* It will run only only a few nanoseconds every time a new {@link
Reference} is enqueued.
*
@@ -87,7 +83,7 @@ public final class ReferenceQueueConsume
* the benefit of the rest of the system, since they make more
resources available sooner.}
*/
private ReferenceQueueConsumer(final DaemonThread lastCreatedDaemon) {
- super(Threads.DAEMONS, "ReferenceQueueConsumer", lastCreatedDaemon);
+ super("ReferenceQueueConsumer", lastCreatedDaemon);
setPriority(Thread.MAX_PRIORITY - 2);
}
@@ -102,8 +98,8 @@ public final class ReferenceQueueConsume
* observed at shutdown time. If the field become null, assume that a
shutdown is
* under way and let the thread terminate.
*/
- ReferenceQueue<T> queue;
- while ((queue = this.queue) != null) {
+ ReferenceQueue<Object> queue;
+ while ((queue = QUEUE) != null) {
try {
/*
* Block until a reference is enqueued. The reference should
never be null
@@ -112,7 +108,7 @@ public final class ReferenceQueueConsume
* may be in the middle of a shutdown. Continue anyway as long
as we didn't
* received the kill event.
*/
- final Reference<? extends T> ref = queue.remove();
+ final Reference<?> ref = queue.remove();
if (ref != null) {
/*
* If the reference does not implement the Disposeable
interface, we want
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Threads.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Threads.java?rev=1429547&r1=1429546&r2=1429547&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Threads.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/Threads.java
Sun Jan 6 16:08:55 2013
@@ -29,9 +29,9 @@ import org.apache.sis.util.logging.Loggi
* threads created by SIS together under the same parent tree node.
*
* {@section Note on dependencies}
- * This class shall not depend on {@link Executors} or {@link
ReferenceQueueConsumer}, because
- * initialization of those classes create new threads or threaded executor.
But it is okay to
- * have dependencies the other way around.
+ * This class shall not depend on {@link ReferenceQueueConsumer} or {@link
DelayedExecutor},
+ * because initialization of those classes create new threads. However it is
okay to have
+ * dependencies the other way around.
*
* @author Martin Desruisseaux (Geomatys)
* @since 0.3 (derived from geotk-3.03)
@@ -84,11 +84,17 @@ final class Threads extends Static {
static DaemonThread lastCreatedDaemon;
/**
- * Executor to shutdown. This is a copy of the {@link
Executors#DAEMON_TASKS} field,
- * copied here only when the {@link Executors} class is loaded and
initialized. We
- * do that way for avoiding dependency from {@code Threads} to {@code
Executors}.
+ * Executor to shutdown. This is a copy of the {@code <removed class>}
executor static final
+ * field, copied here only when the {@code <removed class>} class is
loaded and initialized.
+ * We proceed that way for avoiding dependency from {@code Threads} to
{@code <removed class>}.
+ *
+ * <p>This field has been temporarily fixed to {@code null} since we
removed executor as of
+ * <a href="https://issues.apache.org/jira/browse/SIS-76">SIS-76</a>.
However we may revert
+ * to a modifiable field in a future version if we choose to use executor
again. In the main
+ * time, we declare this field as {@code final} for allowing the Javac
compiler to omit all
+ * compiled code inside {@code if (executor != null)} block.</p>
*/
- static ExecutorService executor;
+ private static final ExecutorService executor = null;
/**
* Do not allows instantiation of this class.
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java?rev=1429547&r1=1429546&r2=1429547&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/Cache.java
Sun Jan 6 16:08:55 2013
@@ -30,13 +30,13 @@ import java.lang.ref.WeakReference;
import java.lang.ref.SoftReference;
import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;
-
import org.apache.sis.util.Disposable;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.resources.Errors;
+import org.apache.sis.internal.util.DelayedRunnable;
import org.apache.sis.internal.util.ReferenceQueueConsumer;
-import static org.apache.sis.internal.util.Executors.executeDaemonTask;
+import static org.apache.sis.internal.util.DelayedExecutor.executeDaemonTask;
/**
@@ -400,7 +400,7 @@ public class Cache<K,V> extends Abstract
* looks for older strong references to replace by weak references so that
the total cost
* stay below the cost limit.
*/
- private final class Strong implements Runnable {
+ private final class Strong extends DelayedRunnable.Immediate {
private final K key;
private final V value;
@@ -438,7 +438,7 @@ public class Cache<K,V> extends Abstract
*/
public Handler<V> lock(final K key) {
final Work handler = new Work(key);
- handler.lock();
+ handler.lock.lock();
Object value;
try {
do {
@@ -454,7 +454,7 @@ public class Cache<K,V> extends Abstract
* values). We are done. But before to leave, lock again
for canceling the
* effect of unlock in the finally clause (we want the
lock to still active).
*/
- handler.lock();
+ handler.lock.lock();
return handler;
}
/*
@@ -487,13 +487,13 @@ public class Cache<K,V> extends Abstract
* handler.
*/
if (map.replace(key, ref, handler)) {
- handler.lock();
+ handler.lock.lock();
return handler;
}
// The map content changed. Try again.
} while (true);
} finally {
- handler.unlock();
+ handler.lock.unlock();
}
/*
* From this point, we abandon our handler.
@@ -508,7 +508,7 @@ public class Cache<K,V> extends Abstract
*/
@SuppressWarnings("unchecked")
final Work work = (Work) value;
- if (work.isHeldByCurrentThread()) {
+ if (work.lock.isHeldByCurrentThread()) {
throw new
IllegalStateException(Errors.format(Errors.Keys.RecursiveCreateCallForKey_1,
key));
}
return work.new Wait();
@@ -620,8 +620,12 @@ public class Cache<K,V> extends Abstract
* A handler implementation used for telling to other threads that the
current thread is
* computing a value.
*/
- @SuppressWarnings("serial") // Actually not intended to be serialized.
- final class Work extends ReentrantLock implements Handler<V>, Runnable {
+ final class Work extends DelayedRunnable.Immediate implements Handler<V> {
+ /**
+ * The synchronization lock.
+ */
+ final ReentrantLock lock;
+
/**
* The key to use for storing the result in the map.
*/
@@ -637,6 +641,7 @@ public class Cache<K,V> extends Abstract
* Creates a new handler which will store the result in the given map
at the given key.
*/
Work(final K key) {
+ lock = new ReentrantLock();
this.key = key;
}
@@ -645,13 +650,13 @@ public class Cache<K,V> extends Abstract
* method should be invoked only from an other thread than the one
doing the calculation.
*/
final V get() {
- if (isHeldByCurrentThread()) {
+ if (lock.isHeldByCurrentThread()) {
throw new IllegalStateException();
}
final V v;
- lock();
+ lock.lock();
v = value;
- unlock();
+ lock.unlock();
return v;
}
@@ -686,7 +691,7 @@ public class Cache<K,V> extends Abstract
done = map.remove(key, this);
}
} finally {
- unlock();
+ lock.unlock();
}
if (done) {
executeDaemonTask(this);
@@ -788,7 +793,7 @@ public class Cache<K,V> extends Abstract
/** Creates a references to be stored in the given map under the given
key. */
Soft(final ConcurrentMap<K,Object> map, final K key, final V value) {
- super(value, ReferenceQueueConsumer.DEFAULT.queue);
+ super(value, ReferenceQueueConsumer.QUEUE);
this.map = map;
this.key = key;
}
@@ -811,7 +816,7 @@ public class Cache<K,V> extends Abstract
/** Creates a references to be stored in the given map under the given
key. */
Weak(final ConcurrentMap<K,Object> map, final K key, final V value) {
- super(value, ReferenceQueueConsumer.DEFAULT.queue);
+ super(value, ReferenceQueueConsumer.QUEUE);
this.map = map;
this.key = key;
}
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/WeakEntry.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/WeakEntry.java?rev=1429547&r1=1429546&r2=1429547&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/WeakEntry.java
(original)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/WeakEntry.java
Sun Jan 6 16:08:55 2013
@@ -80,8 +80,7 @@ abstract class WeakEntry<E> extends Weak
* Constructs a new weak reference.
*/
WeakEntry(final E obj, final WeakEntry<E> next, final int hash) {
- super(obj, ReferenceQueueConsumer.DEFAULT.queue);
- assert ReferenceQueueConsumer.DEFAULT.isAlive();
+ super(obj, ReferenceQueueConsumer.QUEUE);
this.next = next;
this.hash = hash;
}
Modified:
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/collection/CacheTest.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/collection/CacheTest.java?rev=1429547&r1=1429546&r2=1429547&view=diff
==============================================================================
---
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/collection/CacheTest.java
(original)
+++
sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/util/collection/CacheTest.java
Sun Jan 6 16:08:55 2013
@@ -273,7 +273,7 @@ public final strictfp class CacheTest ex
TestUtilities.printSeparator("CacheTest.stress() - testing
concurrent accesses");
out.print("There is "); out.print(threads.length); out.print("
threads, each of them"
+ " fetching or creating "); out.print(count);
out.println(" values.");
- out.println("Number of times a cached value has been reused, for
each thread:");
+ out.println("Number of times a new value has been created, for
each thread:");
for (int i=0; i<threads.length;) {
final String n = String.valueOf(threads[i++].addCount);
out.print(CharSequences.spaces(6 - n.length()));