ThreadPoolImpl.java revision 758:bb6bf34f121f
1314818Sngie/* 2311966Sngie * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. 3311966Sngie * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4311966Sngie * 5311966Sngie * This code is free software; you can redistribute it and/or modify it 6311966Sngie * under the terms of the GNU General Public License version 2 only, as 7311966Sngie * published by the Free Software Foundation. Oracle designates this 8311966Sngie * particular file as subject to the "Classpath" exception as provided 9311966Sngie * by Oracle in the LICENSE file that accompanied this code. 10311966Sngie * 11311966Sngie * This code is distributed in the hope that it will be useful, but WITHOUT 12311966Sngie * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13311966Sngie * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14311966Sngie * version 2 for more details (a copy is included in the LICENSE file that 15311966Sngie * accompanied this code). 16311966Sngie * 17311966Sngie * You should have received a copy of the GNU General Public License version 18311966Sngie * 2 along with this work; if not, write to the Free Software Foundation, 19311966Sngie * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20311966Sngie * 21311966Sngie * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22311966Sngie * or visit www.oracle.com if you need additional information or have any 23311966Sngie * questions. 24311966Sngie */ 25311966Sngie 26311966Sngiepackage com.sun.corba.se.impl.orbutil.threadpool; 27311966Sngie 28311966Sngieimport java.io.IOException; 29311966Sngieimport java.io.Closeable; 30311966Sngie 31311966Sngieimport java.security.AccessController; 32311966Sngieimport java.security.PrivilegedAction; 33311966Sngie 34311966Sngieimport java.util.List; 35311966Sngieimport java.util.ArrayList; 36311966Sngie 37311966Sngieimport java.util.concurrent.atomic.AtomicInteger; 38311966Sngieimport java.util.concurrent.atomic.AtomicLong; 39311966Sngie 40311966Sngieimport com.sun.corba.se.spi.orbutil.threadpool.NoSuchWorkQueueException; 41311966Sngieimport com.sun.corba.se.spi.orbutil.threadpool.ThreadPool; 42311966Sngieimport com.sun.corba.se.spi.orbutil.threadpool.Work; 43311966Sngieimport com.sun.corba.se.spi.orbutil.threadpool.WorkQueue; 44311966Sngie 45311966Sngieimport com.sun.corba.se.impl.orbutil.ORBConstants; 46311966Sngieimport com.sun.corba.se.impl.orbutil.threadpool.WorkQueueImpl; 47311966Sngie 48311966Sngieimport com.sun.corba.se.spi.monitoring.MonitoringConstants; 49311966Sngieimport com.sun.corba.se.spi.monitoring.MonitoredObject; 50311966Sngieimport com.sun.corba.se.spi.monitoring.MonitoringFactories; 51311966Sngieimport com.sun.corba.se.spi.orb.ORB; 52314818Sngieimport com.sun.corba.se.spi.monitoring.LongMonitoredAttributeBase; 53311966Sngie 54311966Sngieimport com.sun.corba.se.impl.logging.ORBUtilSystemException; 55311966Sngieimport com.sun.corba.se.impl.orbutil.ORBConstants; 56311966Sngieimport com.sun.corba.se.spi.logging.CORBALogDomains; 57311966Sngie 58311966Sngiepublic class ThreadPoolImpl implements ThreadPool 59311966Sngie{ 60311966Sngie // serial counter useful for debugging 61311966Sngie private static AtomicInteger threadCounter = new AtomicInteger(0); 62311966Sngie private static final ORBUtilSystemException wrapper = 63311966Sngie ORBUtilSystemException.get(CORBALogDomains.RPC_TRANSPORT); 64311966Sngie 65311966Sngie 66311966Sngie // Any time currentThreadCount and/or availableWorkerThreads is updated 67311966Sngie // or accessed this ThreadPool's WorkQueue must be locked. And, it is 68311966Sngie // expected that this ThreadPool's WorkQueue is the only object that 69311966Sngie // updates and accesses these values directly and indirectly though a 70311966Sngie // call to a method in this ThreadPool. If any call to update or access 71311966Sngie // those values must synchronized on this ThreadPool's WorkQueue. 72311966Sngie private WorkQueue workQueue; 73311966Sngie 74311966Sngie // Stores the number of available worker threads 75311966Sngie private int availableWorkerThreads = 0; 76311966Sngie 77311966Sngie // Stores the number of threads in the threadpool currently 78311966Sngie private int currentThreadCount = 0; 79311966Sngie 80311966Sngie // Minimum number of worker threads created at instantiation of the threadpool 81311966Sngie private int minWorkerThreads = 0; 82311966Sngie 83311966Sngie // Maximum number of worker threads in the threadpool 84311966Sngie private int maxWorkerThreads = 0; 85311966Sngie 86311966Sngie // Inactivity timeout value for worker threads to exit and stop running 87311966Sngie private long inactivityTimeout; 88311966Sngie 89311966Sngie // Indicates if the threadpool is bounded or unbounded 90311966Sngie private boolean boundedThreadPool = false; 91311966Sngie 92311966Sngie // Running count of the work items processed 93311966Sngie // Set the value to 1 so that divide by zero is avoided in 94311966Sngie // averageWorkCompletionTime() 95311966Sngie private AtomicLong processedCount = new AtomicLong(1); 96311966Sngie 97311966Sngie // Running aggregate of the time taken in millis to execute work items 98311966Sngie // processed by the threads in the threadpool 99311966Sngie private AtomicLong totalTimeTaken = new AtomicLong(0); 100311966Sngie 101311966Sngie // Name of the ThreadPool 102311966Sngie private String name; 103311966Sngie 104311966Sngie // MonitoredObject for ThreadPool 105311966Sngie private MonitoredObject threadpoolMonitoredObject; 106311966Sngie 107311966Sngie // ThreadGroup in which threads should be created 108311966Sngie private ThreadGroup threadGroup; 109311966Sngie 110311966Sngie Object workersLock = new Object(); 111311966Sngie List<WorkerThread> workers = new ArrayList<>(); 112311966Sngie 113311966Sngie /** 114311966Sngie * This constructor is used to create an unbounded threadpool 115311966Sngie */ 116311966Sngie public ThreadPoolImpl(ThreadGroup tg, String threadpoolName) { 117311966Sngie inactivityTimeout = ORBConstants.DEFAULT_INACTIVITY_TIMEOUT; 118311966Sngie maxWorkerThreads = Integer.MAX_VALUE; 119311966Sngie workQueue = new WorkQueueImpl(this); 120311966Sngie threadGroup = tg; 121311966Sngie name = threadpoolName; 122311966Sngie initializeMonitoring(); 123311966Sngie } 124311966Sngie 125311966Sngie /** 126311966Sngie * This constructor is used to create an unbounded threadpool 127311966Sngie * in the ThreadGroup of the current thread 128311966Sngie */ 129311966Sngie public ThreadPoolImpl(String threadpoolName) { 130311966Sngie this( Thread.currentThread().getThreadGroup(), threadpoolName ) ; 131311966Sngie } 132311966Sngie 133311966Sngie /** 134311966Sngie * This constructor is used to create bounded threadpool 135311966Sngie */ 136311966Sngie public ThreadPoolImpl(int minSize, int maxSize, long timeout, 137311966Sngie String threadpoolName) 138311966Sngie { 139311966Sngie minWorkerThreads = minSize; 140311966Sngie maxWorkerThreads = maxSize; 141311966Sngie inactivityTimeout = timeout; 142311966Sngie boundedThreadPool = true; 143311966Sngie workQueue = new WorkQueueImpl(this); 144311966Sngie name = threadpoolName; 145311966Sngie for (int i = 0; i < minWorkerThreads; i++) { 146311966Sngie createWorkerThread(); 147311966Sngie } 148311966Sngie initializeMonitoring(); 149311966Sngie } 150311966Sngie 151311966Sngie // Note that this method should not return until AFTER all threads have died. 152311966Sngie public void close() throws IOException { 153311966Sngie 154311966Sngie // Copy to avoid concurrent modification problems. 155311966Sngie List<WorkerThread> copy = null; 156311966Sngie synchronized (workersLock) { 157311966Sngie copy = new ArrayList<>(workers); 158311966Sngie } 159311966Sngie 160311966Sngie for (WorkerThread wt : copy) { 161311966Sngie wt.close(); 162311966Sngie while (wt.getState() != Thread.State.TERMINATED) { 163311966Sngie try { 164311966Sngie wt.join(); 165311966Sngie } catch (InterruptedException exc) { 166311966Sngie wrapper.interruptedJoinCallWhileClosingThreadPool(exc, wt, this); 167311966Sngie } 168311966Sngie } 169311966Sngie } 170311966Sngie 171311966Sngie threadGroup = null; 172311966Sngie } 173311966Sngie 174311966Sngie 175311966Sngie // Setup monitoring for this threadpool 176311966Sngie private void initializeMonitoring() { 177311966Sngie // Get root monitored object 178311966Sngie MonitoredObject root = MonitoringFactories.getMonitoringManagerFactory(). 179311966Sngie createMonitoringManager(MonitoringConstants.DEFAULT_MONITORING_ROOT, null). 180311966Sngie getRootMonitoredObject(); 181311966Sngie 182311966Sngie // Create the threadpool monitoring root 183311966Sngie MonitoredObject threadPoolMonitoringObjectRoot = root.getChild( 184311966Sngie MonitoringConstants.THREADPOOL_MONITORING_ROOT); 185311966Sngie if (threadPoolMonitoringObjectRoot == null) { 186311966Sngie threadPoolMonitoringObjectRoot = MonitoringFactories. 187311966Sngie getMonitoredObjectFactory().createMonitoredObject( 188311966Sngie MonitoringConstants.THREADPOOL_MONITORING_ROOT, 189311966Sngie MonitoringConstants.THREADPOOL_MONITORING_ROOT_DESCRIPTION); 190311966Sngie root.addChild(threadPoolMonitoringObjectRoot); 191311966Sngie } 192311966Sngie threadpoolMonitoredObject = MonitoringFactories. 193311966Sngie getMonitoredObjectFactory(). 194311966Sngie createMonitoredObject(name, 195311966Sngie MonitoringConstants.THREADPOOL_MONITORING_DESCRIPTION); 196311966Sngie 197311966Sngie threadPoolMonitoringObjectRoot.addChild(threadpoolMonitoredObject); 198311966Sngie 199311966Sngie LongMonitoredAttributeBase b1 = new 200311966Sngie LongMonitoredAttributeBase(MonitoringConstants.THREADPOOL_CURRENT_NUMBER_OF_THREADS, 201311966Sngie MonitoringConstants.THREADPOOL_CURRENT_NUMBER_OF_THREADS_DESCRIPTION) { 202311966Sngie public Object getValue() { 203311966Sngie return new Long(ThreadPoolImpl.this.currentNumberOfThreads()); 204311966Sngie } 205311966Sngie }; 206311966Sngie threadpoolMonitoredObject.addAttribute(b1); 207311966Sngie LongMonitoredAttributeBase b2 = new 208311966Sngie LongMonitoredAttributeBase(MonitoringConstants.THREADPOOL_NUMBER_OF_AVAILABLE_THREADS, 209311966Sngie MonitoringConstants.THREADPOOL_CURRENT_NUMBER_OF_THREADS_DESCRIPTION) { 210311966Sngie public Object getValue() { 211311966Sngie return new Long(ThreadPoolImpl.this.numberOfAvailableThreads()); 212311966Sngie } 213311966Sngie }; 214311966Sngie threadpoolMonitoredObject.addAttribute(b2); 215311966Sngie LongMonitoredAttributeBase b3 = new 216311966Sngie LongMonitoredAttributeBase(MonitoringConstants.THREADPOOL_NUMBER_OF_BUSY_THREADS, 217311966Sngie MonitoringConstants.THREADPOOL_NUMBER_OF_BUSY_THREADS_DESCRIPTION) { 218311966Sngie public Object getValue() { 219311966Sngie return new Long(ThreadPoolImpl.this.numberOfBusyThreads()); 220311966Sngie } 221311966Sngie }; 222311966Sngie threadpoolMonitoredObject.addAttribute(b3); 223311966Sngie LongMonitoredAttributeBase b4 = new 224311966Sngie LongMonitoredAttributeBase(MonitoringConstants.THREADPOOL_AVERAGE_WORK_COMPLETION_TIME, 225311966Sngie MonitoringConstants.THREADPOOL_AVERAGE_WORK_COMPLETION_TIME_DESCRIPTION) { 226311966Sngie public Object getValue() { 227311966Sngie return new Long(ThreadPoolImpl.this.averageWorkCompletionTime()); 228311966Sngie } 229311966Sngie }; 230311966Sngie threadpoolMonitoredObject.addAttribute(b4); 231311966Sngie LongMonitoredAttributeBase b5 = new 232311966Sngie LongMonitoredAttributeBase(MonitoringConstants.THREADPOOL_CURRENT_PROCESSED_COUNT, 233311966Sngie MonitoringConstants.THREADPOOL_CURRENT_PROCESSED_COUNT_DESCRIPTION) { 234311966Sngie public Object getValue() { 235311966Sngie return new Long(ThreadPoolImpl.this.currentProcessedCount()); 236311966Sngie } 237311966Sngie }; 238311966Sngie threadpoolMonitoredObject.addAttribute(b5); 239311966Sngie 240311966Sngie // Add the monitored object for the WorkQueue 241311966Sngie 242311966Sngie threadpoolMonitoredObject.addChild( 243311966Sngie ((WorkQueueImpl)workQueue).getMonitoredObject()); 244311966Sngie } 245311966Sngie 246311966Sngie // Package private method to get the monitored object for this 247311966Sngie // class 248311966Sngie MonitoredObject getMonitoredObject() { 249311966Sngie return threadpoolMonitoredObject; 250311966Sngie } 251311966Sngie 252311966Sngie public WorkQueue getAnyWorkQueue() 253311966Sngie { 254311966Sngie return workQueue; 255311966Sngie } 256311966Sngie 257311966Sngie public WorkQueue getWorkQueue(int queueId) 258311966Sngie throws NoSuchWorkQueueException 259311966Sngie { 260311966Sngie if (queueId != 0) 261311966Sngie throw new NoSuchWorkQueueException(); 262311966Sngie return workQueue; 263311966Sngie } 264311966Sngie 265311966Sngie /** 266311966Sngie * To be called from the workqueue when work is added to the 267311966Sngie * workQueue. This method would create new threads if required 268311966Sngie * or notify waiting threads on the queue for available work 269311966Sngie */ 270311966Sngie void notifyForAvailableWork(WorkQueue aWorkQueue) { 271311966Sngie synchronized (aWorkQueue) { 272311966Sngie if (availableWorkerThreads < aWorkQueue.workItemsInQueue()) { 273311966Sngie createWorkerThread(); 274311966Sngie } else { 275311966Sngie aWorkQueue.notify(); 276311966Sngie } 277311966Sngie } 278311966Sngie } 279311966Sngie 280311966Sngie 281311966Sngie private Thread createWorkerThreadHelper( String name ) { 282311966Sngie // Thread creation needs to be in a doPrivileged block 283311966Sngie // if there is a non-null security manager for two reasons: 284311966Sngie // 1. The creation of a thread in a specific ThreadGroup 285311966Sngie // is a privileged operation. Lack of a doPrivileged 286311966Sngie // block here causes an AccessControlException 287311966Sngie // (see bug 6268145). 288311966Sngie // 2. We want to make sure that the permissions associated 289311966Sngie // with this thread do NOT include the permissions of 290311966Sngie // the current thread that is calling this method. 291311966Sngie // This leads to problems in the app server where 292311966Sngie // some threads in the ThreadPool randomly get 293311966Sngie // bad permissions, leading to unpredictable 294311966Sngie // permission errors (see bug 6021011). 295311966Sngie // 296311966Sngie // A Java thread contains a stack of call frames, 297311966Sngie // one for each method called that has not yet returned. 298311966Sngie // Each method comes from a particular class. The class 299311966Sngie // was loaded by a ClassLoader which has an associated 300311966Sngie // CodeSource, and this determines the Permissions 301311966Sngie // for all methods in that class. The current 302311966Sngie // Permissions for the thread are the intersection of 303311966Sngie // all Permissions for the methods on the stack. 304311966Sngie // This is part of the Security Context of the thread. 305311966Sngie // 306311966Sngie // When a thread creates a new thread, the new thread 307311966Sngie // inherits the security context of the old thread. 308311966Sngie // This is bad in a ThreadPool, because different 309311966Sngie // creators of threads may have different security contexts. 310311966Sngie // This leads to occasional unpredictable errors when 311311966Sngie // a thread is re-used in a different security context. 312311966Sngie // 313311966Sngie // Avoiding this problem is simple: just do the thread 314311966Sngie // creation in a doPrivileged block. This sets the 315311966Sngie // inherited security context to that of the code source 316311966Sngie // for the ORB code itself, which contains all permissions 317311966Sngie // in either Java SE or Java EE. 318311966Sngie WorkerThread thread = new WorkerThread(threadGroup, name); 319311966Sngie synchronized (workersLock) { 320311966Sngie workers.add(thread); 321311966Sngie } 322311966Sngie 323311966Sngie // The thread must be set to a daemon thread so the 324311966Sngie // VM can exit if the only threads left are PooledThreads 325311966Sngie // or other daemons. We don't want to rely on the 326311966Sngie // calling thread always being a daemon. 327311966Sngie // Note that no exception is possible here since we 328311966Sngie // are inside the doPrivileged block. 329311966Sngie thread.setDaemon(true); 330311966Sngie 331311966Sngie wrapper.workerThreadCreated(thread, thread.getContextClassLoader()); 332311966Sngie 333311966Sngie thread.start(); 334311966Sngie return null; 335311966Sngie } 336311966Sngie 337311966Sngie 338311966Sngie /** 339311966Sngie * To be called from the workqueue to create worker threads when none 340311966Sngie * available. 341311966Sngie */ 342311966Sngie void createWorkerThread() { 343311966Sngie final String name = getName(); 344311966Sngie synchronized (workQueue) { 345311966Sngie try { 346311966Sngie if (System.getSecurityManager() == null) { 347311966Sngie createWorkerThreadHelper(name); 348311966Sngie } else { 349311966Sngie // If we get here, we need to create a thread. 350311966Sngie AccessController.doPrivileged( 351311966Sngie new PrivilegedAction() { 352311966Sngie public Object run() { 353311966Sngie return createWorkerThreadHelper(name); 354311966Sngie } 355311966Sngie } 356311966Sngie ); 357311966Sngie } 358311966Sngie } catch (Throwable t) { 359311966Sngie // Decrementing the count of current worker threads. 360311966Sngie // But, it will be increased in the finally block. 361311966Sngie decrementCurrentNumberOfThreads(); 362311966Sngie wrapper.workerThreadCreationFailure(t); 363311966Sngie } finally { 364311966Sngie incrementCurrentNumberOfThreads(); 365311966Sngie } 366311966Sngie } 367311966Sngie } 368311966Sngie 369311966Sngie public int minimumNumberOfThreads() { 370311966Sngie return minWorkerThreads; 371311966Sngie } 372311966Sngie 373311966Sngie public int maximumNumberOfThreads() { 374311966Sngie return maxWorkerThreads; 375311966Sngie } 376311966Sngie 377311966Sngie public long idleTimeoutForThreads() { 378311966Sngie return inactivityTimeout; 379311966Sngie } 380311966Sngie 381311966Sngie public int currentNumberOfThreads() { 382311966Sngie synchronized (workQueue) { 383311966Sngie return currentThreadCount; 384311966Sngie } 385311966Sngie } 386311966Sngie 387311966Sngie void decrementCurrentNumberOfThreads() { 388311966Sngie synchronized (workQueue) { 389311966Sngie currentThreadCount--; 390311966Sngie } 391311966Sngie } 392311966Sngie 393311966Sngie void incrementCurrentNumberOfThreads() { 394311966Sngie synchronized (workQueue) { 395311966Sngie currentThreadCount++; 396311966Sngie } 397311966Sngie } 398311966Sngie 399311966Sngie public int numberOfAvailableThreads() { 400311966Sngie synchronized (workQueue) { 401311966Sngie return availableWorkerThreads; 402311966Sngie } 403311966Sngie } 404311966Sngie 405311966Sngie public int numberOfBusyThreads() { 406311966Sngie synchronized (workQueue) { 407311966Sngie return (currentThreadCount - availableWorkerThreads); 408311966Sngie } 409311966Sngie } 410311966Sngie 411311966Sngie public long averageWorkCompletionTime() { 412311966Sngie synchronized (workQueue) { 413311966Sngie return (totalTimeTaken.get() / processedCount.get()); 414311966Sngie } 415311966Sngie } 416311966Sngie 417311966Sngie public long currentProcessedCount() { 418311966Sngie synchronized (workQueue) { 419311966Sngie return processedCount.get(); 420311966Sngie } 421311966Sngie } 422311966Sngie 423311966Sngie public String getName() { 424311966Sngie return name; 425311966Sngie } 426311966Sngie 427311966Sngie /** 428311966Sngie * This method will return the number of WorkQueues serviced by the threadpool. 429311966Sngie */ 430311966Sngie public int numberOfWorkQueues() { 431311966Sngie return 1; 432311966Sngie } 433311966Sngie 434311966Sngie 435311966Sngie private static synchronized int getUniqueThreadId() { 436311966Sngie return ThreadPoolImpl.threadCounter.incrementAndGet(); 437311966Sngie } 438311966Sngie 439311966Sngie /** 440311966Sngie * This method will decrement the number of available threads 441311966Sngie * in the threadpool which are waiting for work. Called from 442311966Sngie * WorkQueueImpl.requestWork() 443311966Sngie */ 444311966Sngie void decrementNumberOfAvailableThreads() { 445311966Sngie synchronized (workQueue) { 446311966Sngie availableWorkerThreads--; 447311966Sngie } 448311966Sngie } 449311966Sngie 450311966Sngie /** 451311966Sngie * This method will increment the number of available threads 452311966Sngie * in the threadpool which are waiting for work. Called from 453311966Sngie * WorkQueueImpl.requestWork() 454311966Sngie */ 455311966Sngie void incrementNumberOfAvailableThreads() { 456311966Sngie synchronized (workQueue) { 457311966Sngie availableWorkerThreads++; 458311966Sngie } 459311966Sngie } 460311966Sngie 461311966Sngie 462311966Sngie private class WorkerThread extends Thread implements Closeable 463311966Sngie { 464311966Sngie private Work currentWork; 465311966Sngie private int threadId = 0; // unique id for the thread 466311966Sngie private volatile boolean closeCalled = false; 467311966Sngie private String threadPoolName; 468311966Sngie // name seen by Thread.getName() 469311966Sngie private StringBuffer workerThreadName = new StringBuffer(); 470311966Sngie 471311966Sngie WorkerThread(ThreadGroup tg, String threadPoolName) { 472311966Sngie super(tg, null, "Idle", 0, false); 473311966Sngie this.threadId = ThreadPoolImpl.getUniqueThreadId(); 474311966Sngie this.threadPoolName = threadPoolName; 475311966Sngie setName(composeWorkerThreadName(threadPoolName, "Idle")); 476311966Sngie } 477311966Sngie 478311966Sngie public synchronized void close() { 479311966Sngie closeCalled = true; 480311966Sngie interrupt(); 481311966Sngie } 482311966Sngie 483311966Sngie private void resetClassLoader() { 484311966Sngie 485311966Sngie } 486311966Sngie 487311966Sngie private void performWork() { 488311966Sngie long start = System.currentTimeMillis(); 489311966Sngie try { 490311966Sngie currentWork.doWork(); 491311966Sngie } catch (Throwable t) { 492311966Sngie wrapper.workerThreadDoWorkThrowable(this, t); 493311966Sngie } 494311966Sngie long elapsedTime = System.currentTimeMillis() - start; 495311966Sngie totalTimeTaken.addAndGet(elapsedTime); 496311966Sngie processedCount.incrementAndGet(); 497311966Sngie } 498311966Sngie 499311966Sngie public void run() { 500311966Sngie try { 501311966Sngie while (!closeCalled) { 502311966Sngie try { 503311966Sngie currentWork = ((WorkQueueImpl)workQueue).requestWork( 504311966Sngie inactivityTimeout); 505311966Sngie if (currentWork == null) 506311966Sngie continue; 507311966Sngie } catch (InterruptedException exc) { 508311966Sngie wrapper.workQueueThreadInterrupted( exc, getName(), 509311966Sngie Boolean.valueOf(closeCalled)); 510311966Sngie 511311966Sngie continue ; 512311966Sngie } catch (Throwable t) { 513311966Sngie wrapper.workerThreadThrowableFromRequestWork(this, t, 514311966Sngie workQueue.getName()); 515311966Sngie 516311966Sngie continue; 517311966Sngie } 518311966Sngie 519311966Sngie performWork(); 520311966Sngie 521311966Sngie // set currentWork to null so that the work item can be 522311966Sngie // garbage collected without waiting for the next work item. 523311966Sngie currentWork = null; 524311966Sngie 525311966Sngie resetClassLoader(); 526311966Sngie } 527311966Sngie } catch (Throwable e) { 528311966Sngie // This should not be possible 529311966Sngie wrapper.workerThreadCaughtUnexpectedThrowable(this,e); 530311966Sngie } finally { 531311966Sngie synchronized (workersLock) { 532311966Sngie workers.remove(this); 533311966Sngie } 534311966Sngie } 535311966Sngie } 536311966Sngie 537311966Sngie private String composeWorkerThreadName(String poolName, String workerName) { 538311966Sngie workerThreadName.setLength(0); 539311966Sngie workerThreadName.append("p: ").append(poolName); 540311966Sngie workerThreadName.append("; w: ").append(workerName); 541311966Sngie return workerThreadName.toString(); 542311966Sngie } 543311966Sngie } // End of WorkerThread class 544311966Sngie 545311966Sngie} 546311966Sngie 547311966Sngie// End of file. 548311966Sngie