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