# HG changeset patch # User dfuchs # Date 1236635361 -3600 # Node ID cc0bbd192d1a69c768572a2d48b817d07819ed4d # Parent c22bf553c8190ed4266269ab844746aaf023d239 6610896: JMX Monitor handles thread groups incorrectly Reviewed-by: emcmanus diff -r c22bf553c819 -r cc0bbd192d1a jdk/src/share/classes/javax/management/monitor/Monitor.java --- a/jdk/src/share/classes/javax/management/monitor/Monitor.java Fri Mar 06 12:40:38 2009 +0300 +++ b/jdk/src/share/classes/javax/management/monitor/Monitor.java Mon Mar 09 22:49:21 2009 +0100 @@ -33,8 +33,9 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; @@ -174,14 +175,20 @@ new DaemonThreadFactory("Scheduler")); /** + * Map containing the thread pool executor per thread group. + */ + private static final Map executors = + new WeakHashMap(); + + /** + * Lock for executors map. + */ + private static final Object executorsLock = new Object(); + + /** * Maximum Pool Size */ private static final int maximumPoolSize; - - /** - * Executor Service. - */ - private static final ExecutorService executor; static { final String maximumPoolSizeSysProp = "jmx.x.monitor.maximum.pool.size"; final String maximumPoolSizeStr = AccessController.doPrivileged( @@ -211,22 +218,9 @@ maximumPoolSize = maximumPoolSizeTmp; } } - executor = new ThreadPoolExecutor( - maximumPoolSize, - maximumPoolSize, - 60L, - TimeUnit.SECONDS, - new LinkedBlockingQueue(), - new DaemonThreadFactory("Executor")); - ((ThreadPoolExecutor)executor).allowCoreThreadTimeOut(true); } /** - * Monitor task to be executed by the Executor Service. - */ - private final MonitorTask monitorTask = new MonitorTask(); - - /** * Future associated to the current monitor task. */ private Future monitorFuture; @@ -234,7 +228,7 @@ /** * Scheduler task to be executed by the Scheduler Service. */ - private final SchedulerTask schedulerTask = new SchedulerTask(monitorTask); + private final SchedulerTask schedulerTask = new SchedulerTask(); /** * ScheduledFuture associated to the current scheduler task. @@ -720,6 +714,7 @@ // Start the scheduler. // cleanupFutures(); + schedulerTask.setMonitorTask(new MonitorTask()); schedulerFuture = scheduler.schedule(schedulerTask, getGranularityPeriod(), TimeUnit.MILLISECONDS); @@ -1468,7 +1463,7 @@ */ private class SchedulerTask implements Runnable { - private Runnable task = null; + private MonitorTask task; /* * ------------------------------------------ @@ -1476,7 +1471,16 @@ * ------------------------------------------ */ - public SchedulerTask(Runnable task) { + public SchedulerTask() { + } + + /* + * ------------------------------------------ + * GETTERS/SETTERS + * ------------------------------------------ + */ + + public void setMonitorTask(MonitorTask task) { this.task = task; } @@ -1488,7 +1492,7 @@ public void run() { synchronized (Monitor.this) { - Monitor.this.monitorFuture = executor.submit(task); + Monitor.this.monitorFuture = task.submit(); } } } @@ -1501,6 +1505,8 @@ */ private class MonitorTask implements Runnable { + private ThreadPoolExecutor executor; + /* * ------------------------------------------ * CONSTRUCTORS @@ -1508,6 +1514,38 @@ */ public MonitorTask() { + // Find out if there's already an existing executor for the calling + // thread and reuse it. Otherwise, create a new one and store it in + // the executors map. If there is a SecurityManager, the group of + // System.getSecurityManager() is used, else the group of the thread + // instantiating this MonitorTask, i.e. the group of the thread that + // calls "Monitor.start()". + SecurityManager s = System.getSecurityManager(); + ThreadGroup group = (s != null) ? s.getThreadGroup() : + Thread.currentThread().getThreadGroup(); + synchronized (executorsLock) { + for (ThreadPoolExecutor e : executors.keySet()) { + DaemonThreadFactory tf = + (DaemonThreadFactory) e.getThreadFactory(); + ThreadGroup tg = tf.getThreadGroup(); + if (tg == group) { + executor = e; + break; + } + } + if (executor == null) { + executor = new ThreadPoolExecutor( + maximumPoolSize, + maximumPoolSize, + 60L, + TimeUnit.SECONDS, + new LinkedBlockingQueue(), + new DaemonThreadFactory("ThreadGroup<" + + group.getName() + "> Executor", group)); + executor.allowCoreThreadTimeOut(true); + executors.put(executor, null); + } + } } /* @@ -1516,6 +1554,10 @@ * ------------------------------------------ */ + public Future submit() { + return executor.submit(this); + } + public void run() { final ScheduledFuture sf; synchronized (Monitor.this) { @@ -1574,6 +1616,15 @@ namePrefix = "JMX Monitor " + poolName + " Pool [Thread-"; } + public DaemonThreadFactory(String poolName, ThreadGroup threadGroup) { + group = threadGroup; + namePrefix = "JMX Monitor " + poolName + " Pool [Thread-"; + } + + public ThreadGroup getThreadGroup() { + return group; + } + public Thread newThread(Runnable r) { Thread t = new Thread(group, r,