Author: peter_firmstone Date: Tue Feb 19 10:19:39 2013 New Revision: 1447656
URL: http://svn.apache.org/r1447656 Log: Minor refactoring Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/thread/NewThreadAction.java river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/thread/ThreadPool.java river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/DiscoveryEvent.java river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/LookupDiscovery.java Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/thread/NewThreadAction.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/thread/NewThreadAction.java?rev=1447656&r1=1447655&r2=1447656&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/thread/NewThreadAction.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/thread/NewThreadAction.java Tue Feb 19 10:19:39 2013 @@ -1,137 +1,137 @@ -/* - * 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 com.sun.jini.thread; - -import java.security.AccessController; -import java.security.Permission; -import java.security.PrivilegedAction; - -/** - * A PrivilegedAction for creating a new thread conveniently with an - * AccessController.doPrivileged or Security.doPrivileged. - * - * All constructors allow the choice of the Runnable for the new - * thread to execute, the name of the new thread (which will be - * prefixed with the constant NAME_PREFIX), and whether or not it will - * be a daemon thread. - * - * The new thread may be created in the system thread group (the root - * of the thread group tree) or an internally created non-system - * thread group, as specified at construction of this class. - * - * The new thread will have the system class loader as its initial - * context class loader (that is, its context class loader will NOT be - * inherited from the current thread). - * - * @author Sun Microsystems, Inc. - **/ -public final class NewThreadAction implements PrivilegedAction { - - static final String NAME_PREFIX = "(JSK) "; - - /** cached reference to the system (root) thread group */ - static final ThreadGroup systemThreadGroup = (ThreadGroup) - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - ThreadGroup group = Thread.currentThread().getThreadGroup(); - ThreadGroup parent; - while ((parent = group.getParent()) != null) { - group = parent; - } - return group; - } - }); - - /** - * special child of the system thread group for running tasks that - * may execute user code, so that the security policy for threads in - * the system thread group will not apply - */ - static final ThreadGroup userThreadGroup = (ThreadGroup) - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - return new ThreadGroup(systemThreadGroup, - NAME_PREFIX + "Runtime"); - } - }); - - private static final Permission getClassLoaderPermission = - new RuntimePermission("getClassLoader"); - - private final ThreadGroup group; - private final Runnable runnable; - private final String name; - private final boolean daemon; - - NewThreadAction(ThreadGroup group, Runnable runnable, - String name, boolean daemon) - { - this.group = group; - this.runnable = runnable; - this.name = name; - this.daemon = daemon; - } - - /** - * Creates an action that will create a new thread in the - * system thread group. - * - * @param runnable the Runnable for the new thread to execute - * - * @param name the name of the new thread - * - * @param daemon if true, new thread will be a daemon thread; - * if false, new thread will not be a daemon thread - */ - public NewThreadAction(Runnable runnable, String name, boolean daemon) { - this(systemThreadGroup, runnable, name, daemon); - } - - /** - * Creates an action that will create a new thread. - * - * @param runnable the Runnable for the new thread to execute - * - * @param name the name of the new thread - * - * @param daemon if true, new thread will be a daemon thread; - * if false, new thread will not be a daemon thread - * - * @param user if true, thread will be created in a non-system - * thread group; if false, thread will be created in the system - * thread group - */ - public NewThreadAction(Runnable runnable, String name, boolean daemon, - boolean user) - { - this(user ? userThreadGroup : systemThreadGroup, - runnable, name, daemon); - } - - public Object run() { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(getClassLoaderPermission); - } - Thread t = new Thread(group, runnable, NAME_PREFIX + name); - t.setContextClassLoader(ClassLoader.getSystemClassLoader()); - t.setDaemon(daemon); - return t; - } -} +/* + * 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 com.sun.jini.thread; + +import java.security.AccessController; +import java.security.Permission; +import java.security.PrivilegedAction; + +/** + * A PrivilegedAction for creating a new thread conveniently with an + * AccessController.doPrivileged or Security.doPrivileged. + * + * All constructors allow the choice of the Runnable for the new + * thread to execute, the name of the new thread (which will be + * prefixed with the constant NAME_PREFIX), and whether or not it will + * be a daemon thread. + * + * The new thread may be created in the system thread group (the root + * of the thread group tree) or an internally created non-system + * thread group, as specified at construction of this class. + * + * The new thread will have the system class loader as its initial + * context class loader (that is, its context class loader will NOT be + * inherited from the current thread). + * + * @author Sun Microsystems, Inc. + **/ +public final class NewThreadAction implements PrivilegedAction<Thread> { + + static final String NAME_PREFIX = "(JSK) "; + + /** cached reference to the system (root) thread group */ + static final ThreadGroup systemThreadGroup = + AccessController.doPrivileged(new PrivilegedAction<ThreadGroup>() { + public ThreadGroup run() { + ThreadGroup group = Thread.currentThread().getThreadGroup(); + ThreadGroup parent; + while ((parent = group.getParent()) != null) { + group = parent; + } + return group; + } + }); + + /** + * special child of the system thread group for running tasks that + * may execute user code, so that the security policy for threads in + * the system thread group will not apply + */ + static final ThreadGroup userThreadGroup = + AccessController.doPrivileged(new PrivilegedAction<ThreadGroup>() { + public ThreadGroup run() { + return new ThreadGroup(systemThreadGroup, + NAME_PREFIX + "Runtime"); + } + }); + + private static final Permission getClassLoaderPermission = + new RuntimePermission("getClassLoader"); + + private final ThreadGroup group; + private final Runnable runnable; + private final String name; + private final boolean daemon; + + NewThreadAction(ThreadGroup group, Runnable runnable, + String name, boolean daemon) + { + this.group = group; + this.runnable = runnable; + this.name = name; + this.daemon = daemon; + } + + /** + * Creates an action that will create a new thread in the + * system thread group. + * + * @param runnable the Runnable for the new thread to execute + * + * @param name the name of the new thread + * + * @param daemon if true, new thread will be a daemon thread; + * if false, new thread will not be a daemon thread + */ + public NewThreadAction(Runnable runnable, String name, boolean daemon) { + this(systemThreadGroup, runnable, name, daemon); + } + + /** + * Creates an action that will create a new thread. + * + * @param runnable the Runnable for the new thread to execute + * + * @param name the name of the new thread + * + * @param daemon if true, new thread will be a daemon thread; + * if false, new thread will not be a daemon thread + * + * @param user if true, thread will be created in a non-system + * thread group; if false, thread will be created in the system + * thread group + */ + public NewThreadAction(Runnable runnable, String name, boolean daemon, + boolean user) + { + this(user ? userThreadGroup : systemThreadGroup, + runnable, name, daemon); + } + + public Thread run() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(getClassLoaderPermission); + } + Thread t = new Thread(group, runnable, NAME_PREFIX + name); + t.setContextClassLoader(ClassLoader.getSystemClassLoader()); + t.setDaemon(daemon); + return t; + } +} Modified: river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/thread/ThreadPool.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/thread/ThreadPool.java?rev=1447656&r1=1447655&r2=1447656&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/thread/ThreadPool.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/com/sun/jini/thread/ThreadPool.java Tue Feb 19 10:19:39 2013 @@ -1,172 +1,207 @@ -/* - * 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 com.sun.jini.thread; - -import com.sun.jini.action.GetLongAction; -import java.security.AccessController; -import java.util.LinkedList; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * ThreadPool is a simple thread pool implementation of the Executor - * interface. - * - * A new task is always given to an idle thread, if one is available; - * otherwise, a new thread is always created. There is no minimum - * warm thread count, nor is there a maximum thread count (tasks are - * never queued unless there are sufficient idle threads to execute - * them). - * - * New threads are created as daemon threads in the thread group that - * was passed to the ThreadPool instance's constructor. Each thread's - * name is the prefix NewThreadAction.NAME_PREFIX followed by the name - * of the task it is currently executing, or "Idle" if it is currently - * idle. - * - * <p>This implementation uses the {@link Logger} named - * <code>com.sun.jini.thread.ThreadPool</code> to - * log information at the following levels: - * - * <p><table summary="Describes what is logged by ThreadPool at - * various logging levels" border=1 cellpadding=5> - * - * <tr> <th> Level <th> Description - * - * <tr> <td> {@link Level#WARNING WARNING} <td> uncaught exception in - * worker thread - * - * </table> - * - * @author Sun Microsystems, Inc. - **/ -final class ThreadPool implements Executor, java.util.concurrent.Executor { - - /** how long a thread waits in the idle state before passing away */ - private static final long idleTimeout = // default 5 minutes - ((Long) AccessController.doPrivileged(new GetLongAction( - "com.sun.jini.thread.idleThreadTimeout", 300000))) - .longValue(); - - private static final Logger logger = - Logger.getLogger("com.sun.jini.thread.ThreadPool"); - - /** thread group that this pool's threads execute in */ - private final ThreadGroup threadGroup; - - /** lock guarding all mutable instance state (below) */ - private final Object lock = new Object(); - - /** threads definitely available to take new tasks */ - private int idleThreads = 0; - - /** queues of tasks to execute */ - private final LinkedList queue = new LinkedList(); - - /** - * Creates a new thread group that executes tasks in threads of - * the given thread group. - */ - ThreadPool(ThreadGroup threadGroup) { - this.threadGroup = threadGroup; - } - - public void execute(Runnable runnable, String name) { - Task task = new Task(runnable, name); - synchronized (lock) { - if (queue.size() < idleThreads) { - queue.addLast(task); - lock.notify(); - return; - } - } - Thread t = (Thread) AccessController.doPrivileged( - new NewThreadAction(threadGroup, new Worker(task), name, true)); - t.start(); - } - - public void execute(Runnable command) { - execute(command, "com.sun.jini.thread.ThreadPool"); - } - - /** - * Task simply encapsulates a task's Runnable object with its name. - */ - private static class Task { - - final Runnable runnable; - final String name; - - Task(Runnable runnable, String name) { - this.runnable = runnable; - this.name = name; - } - } - - /** - * Worker executes an initial task, and then it executes tasks from the - * queue, passing away if ever idle for more than the idle timeout value. - */ - private class Worker implements Runnable { - - private Task first; - - Worker(Task first) { - this.first = first; - } - - public void run() { - Task task = first; - first = null; - - while (true) { - try { - task.runnable.run(); - } catch (Throwable t) { - logger.log(Level.WARNING, "uncaught exception", t); - } - /* - * REMIND: What if the task changed this thread's - * priority? or context class loader? - */ - - synchronized (lock) { - if (queue.isEmpty()) { - Thread.currentThread().setName( - NewThreadAction.NAME_PREFIX + "Idle"); - idleThreads++; - try { - lock.wait(idleTimeout); - } catch (InterruptedException e) { - // ignore interrupts at this level - } finally { - idleThreads--; - } - if (queue.isEmpty()) { - break; // timed out - } - } - task = (Task) queue.removeFirst(); - Thread.currentThread().setName( - NewThreadAction.NAME_PREFIX + task.name); - } - }; - } - } -} +/* + * 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 com.sun.jini.thread; + +import com.sun.jini.action.GetLongAction; +import java.security.AccessController; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * ThreadPool is a simple thread pool implementation of the Executor + * interface. + * + * A new task is always given to an idle thread, if one is available; + * otherwise, a new thread is always created. There is no minimum + * warm thread count, nor is there a maximum thread count (tasks are + * never queued unless there are sufficient idle threads to execute + * them). + * + * New threads are created as daemon threads in the thread group that + * was passed to the ThreadPool instance's constructor. Each thread's + * name is the prefix NewThreadAction.NAME_PREFIX followed by the name + * of the task it is currently executing, or "Idle" if it is currently + * idle. + * + * <p>This implementation uses the {@link Logger} named + * <code>com.sun.jini.thread.ThreadPool</code> to + * log information at the following levels: + * + * <p><table summary="Describes what is logged by ThreadPool at + * various logging levels" border=1 cellpadding=5> + * + * <tr> <th> Level <th> Description + * + * <tr> <td> {@link Level#WARNING WARNING} <td> uncaught exception in + * worker thread + * + * </table> + * + * @author Sun Microsystems, Inc. + **/ +final class ThreadPool implements Executor, java.util.concurrent.Executor { + + /** how long a thread waits in the idle state before passing away */ + private static final long idleTimeout = // default 5 minutes + ((Long) AccessController.doPrivileged(new GetLongAction( + "com.sun.jini.thread.idleThreadTimeout", 300000))) + .longValue(); + + private static final Logger logger = + Logger.getLogger("com.sun.jini.thread.ThreadPool"); + + /** thread group that this pool's threads execute in */ + private final ThreadGroup threadGroup; + + /** Lock used to wake idle threads and synchronize writes to idleThreads */ + private final Lock lock; + private final Condition wakeup; + + /** threads definitely available to take new tasks */ + private volatile int idleThreads; + + /** queues of tasks to execute */ + private final Queue<Runnable> queue; + + /** + * Creates a new thread group that executes tasks in threads of + * the given thread group. + */ + ThreadPool(ThreadGroup threadGroup) { + this.threadGroup = threadGroup; + idleThreads = 0; + queue = new ConcurrentLinkedQueue<Runnable>(); //Non blocking queue. + lock = new ReentrantLock(); + wakeup = lock.newCondition(); + } + + // This method must not block - Executor + public void execute(Runnable runnable, String name) { + Runnable task = new Task(runnable, name); + if (idleThreads < 3){ // create a new thread, non blocking approximate + Thread t = AccessController.doPrivileged( + new NewThreadAction(threadGroup, new Worker(task), name, true)); + t.start(); + } else { + boolean accepted = queue.offer(task); //non blocking. + if (accepted) { + lock.lock(); // blocking. + try { + wakeup.signal(); + } finally { + lock.unlock(); + } + } else { // Should never happen. + Thread t = AccessController.doPrivileged( + new NewThreadAction(threadGroup, new Worker(task), name, true)); + t.start(); + } + } + } + + public void execute(Runnable command) { + execute(command, "com.sun.jini.thread.ThreadPool"); + } + + /** + * Task simply encapsulates a task's Runnable object with its name. + */ + private static class Task implements Runnable{ + + private final Runnable runnable; + private final String name; + + Task(Runnable runnable, String name) { + this.runnable = runnable; + this.name = name; + } + + public void run(){ + try { + runnable.run(); + } catch (Exception t) { // Don't catch Error + logger.log(Level.WARNING, "uncaught exception", t); + if (t instanceof RuntimeException){ + if (t instanceof SecurityException){ + // ignore it will be logged. + } else { + // Ignorance of RuntimeException is generally bad, bail out. + throw (RuntimeException) t; + } + } + } + } + + public String toString(){ + return name; + } + } + + /** + * Worker executes an initial task, and then it executes tasks from the + * queue, passing away if ever idle for more than the idle timeout value. + */ + private class Worker implements Runnable { + + private volatile Runnable first; + + Worker(Runnable first) { + this.first = first; + } + + public void run() { + Runnable task = first; + first = null; // For garbage collection. + task.run(); + Thread thread = Thread.currentThread(); + while (!thread.isInterrupted()) { + /* + * REMIND: What if the task changed this thread's + * priority? or context class loader? + */ + for ( task = queue.poll(); task != null; task = queue.poll()){ + // Keep executing while tasks are available. + thread.setName(NewThreadAction.NAME_PREFIX + task); + task.run(); + } + // queue is empty; + thread.setName(NewThreadAction.NAME_PREFIX + "Idle"); + lock.lock(); + try { + idleThreads++; + wakeup.await(idleTimeout, TimeUnit.MILLISECONDS);// releases lock and obtains when woken. + // Allow thread to expire if queue empty after waking. + if (queue.peek() == null) thread.interrupt(); + } catch (InterruptedException ex) { + // Interrupt thread, another thread can pick up tasks. + thread.interrupt(); + } finally { + idleThreads--; + lock.unlock(); + } + } + } + } + } Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/DiscoveryEvent.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/DiscoveryEvent.java?rev=1447656&r1=1447655&r2=1447656&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/DiscoveryEvent.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/DiscoveryEvent.java Tue Feb 19 10:19:39 2013 @@ -17,7 +17,10 @@ */ package net.jini.discovery; +import java.io.IOException; +import java.io.ObjectInputStream; import java.util.EventObject; +import java.util.HashMap; import java.util.Map; import net.jini.core.lookup.ServiceRegistrar; @@ -44,7 +47,7 @@ public class DiscoveryEvent extends Even * * @serial */ - protected ServiceRegistrar[] regs; + private ServiceRegistrar[] regs; /** * Map from the registrars of this event to the groups in which each @@ -52,7 +55,7 @@ public class DiscoveryEvent extends Even * * @serial */ - protected Map groups; + private Map groups; /** * Construct a new <code>DiscoveryEvent</code> object, with the given @@ -64,7 +67,7 @@ public class DiscoveryEvent extends Even */ public DiscoveryEvent(Object source, ServiceRegistrar[] regs) { super(source); - this.regs = regs; + this.regs = regs.clone(); this.groups = null; } @@ -91,7 +94,7 @@ public class DiscoveryEvent extends Even * @return the set of registrars to which this event applies. */ public ServiceRegistrar[] getRegistrars() { - return regs; + return regs.clone(); } /** @@ -114,6 +117,13 @@ public class DiscoveryEvent extends Even * registrar. */ public Map getGroups() { - return groups; + return groups != null ? new HashMap(groups) : null; + } + + @SuppressWarnings("unchecked") + private void readObject(ObjectInputStream oin) throws IOException, ClassNotFoundException{ + oin.defaultReadObject(); + regs = regs.clone(); + if (groups != null) groups = new HashMap(groups); } } Modified: river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/LookupDiscovery.java URL: http://svn.apache.org/viewvc/river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/LookupDiscovery.java?rev=1447656&r1=1447655&r2=1447656&view=diff ============================================================================== --- river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/LookupDiscovery.java (original) +++ river/jtsk/skunk/qa_refactor/trunk/src/net/jini/discovery/LookupDiscovery.java Tue Feb 19 10:19:39 2013 @@ -1796,11 +1796,11 @@ public class LookupDiscovery implements InetAddress addr, int port) { - logger.log( + logger.log( Levels.HANDLED, "Exception occured during unicast discovery " + addr + ":" + port, e); - } + } }.getResponse(loc.getHost(), loc.getPort(), rawUnicastDiscoveryConstraints); @@ -1875,11 +1875,6 @@ public class LookupDiscovery implements logger.finest("LookupDiscovery - UnicastDiscoveryTask completed"); }//end run - /** Returns true if current instance must be run after task(s) in - * task manager queue. - * @param tasks the tasks to consider. - * @param size elements with index less than size are considered. - */ }//end class UnicastDiscoveryTask /**
