1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 module hunt.pool.impl.EvictionTimer; 18 19 import hunt.pool.impl.BaseGenericObjectPool; 20 21 import hunt.concurrency.thread; 22 import hunt.concurrency.Delayed; 23 import hunt.concurrency.Future; 24 import hunt.concurrency.ScheduledThreadPoolExecutor; 25 import hunt.concurrency.ThreadFactory; 26 27 import hunt.Exceptions; 28 import hunt.logging.ConsoleLogger; 29 import hunt.util.Common; 30 import hunt.util.Runnable; 31 import hunt.util.StringBuilder; 32 33 import core.thread; 34 import core.time; 35 36 /** 37 * Provides a shared idle object eviction timer for all pools. 38 * <p> 39 * This class is currently implemented using {@link ScheduledThreadPoolExecutor}. This implementation may change in any 40 * future release. This class keeps track of how many pools are using it. If no pools are using the timer, it is 41 * cancelled. This prevents a thread being left running which, in application server environments, can lead to memory 42 * leads and/or prevent applications from shutting down or reloading cleanly. 43 * </p> 44 * <p> 45 * This class has package scope to prevent its inclusion in the pool public API. The class declaration below should 46 * *not* be changed to public. 47 * </p> 48 * <p> 49 * This class is intended to be thread-safe. 50 * </p> 51 * 52 */ 53 class EvictionTimer { 54 55 /** Executor instance */ 56 private __gshared ScheduledThreadPoolExecutor executor; //@GuardedBy("EvictionTimer.class") 57 58 /** Prevent instantiation */ 59 private this() { 60 // Hide the default constructor 61 } 62 63 64 /** 65 */ 66 override 67 string toString() { 68 StringBuilder builder = new StringBuilder(); 69 builder.append("EvictionTimer []"); 70 return builder.toString(); 71 } 72 73 74 /** 75 * Add the specified eviction task to the timer. Tasks that are added with a 76 * call to this method *must* call {@link #cancel(TimerTask)} to cancel the 77 * task to prevent memory and/or thread leaks in application server 78 * environments. 79 * 80 * @param task Task to be scheduled 81 * @param delay Delay in milliseconds before task is executed 82 * @param period Time in milliseconds between executions 83 */ 84 static void schedule(BaseGenericObjectPool.Evictor task, long delay, long period) { 85 if (executor is null) { 86 executor = new ScheduledThreadPoolExecutor(1, new EvictorThreadFactory()); 87 executor.setRemoveOnCancelPolicy(true); 88 } 89 IFuture scheduledFuture = 90 executor.scheduleWithFixedDelay(task, delay.msecs, period.msecs); 91 task.setScheduledFuture(scheduledFuture); 92 } 93 94 /** 95 * Remove the specified eviction task from the timer. 96 * 97 * @param evictor Task to be cancelled 98 * @param timeout If the associated executor is no longer required, how 99 * long should this thread wait for the executor to 100 * terminate? 101 * @param unit The units for the specified timeout 102 */ 103 static synchronized void cancel(BaseGenericObjectPool.Evictor evictor, Duration timeout) { 104 if (evictor !is null) { 105 evictor.cancel(); 106 } 107 if (executor !is null && executor.getQueue().isEmpty()) { 108 executor.shutdown(); 109 try { 110 // executor.awaitTermination(timeout); 111 // TODO: Tasks pending completion -@zhangxueping at 2019-12-06T16:11:54+08:00 112 // 113 } catch (InterruptedException e) { 114 version(HUNT_DEBUG) warning(e.msg); 115 // Swallow 116 // Significant API changes would be required to propagate this 117 } 118 executor.setCorePoolSize(0); 119 executor = null; 120 } 121 } 122 123 /** 124 * Thread factory that creates a daemon thread, with the context class loader from this class. 125 */ 126 private static class EvictorThreadFactory : ThreadFactory { 127 128 Thread newThread(Runnable runnable) { 129 ThreadEx thread = new ThreadEx(null, runnable, "commons-pool-evictor-thread"); 130 thread.setDaemon(true); // POOL-363 - Required for applications using Runtime.addShutdownHook(). --joshlandin 03.27.2019 131 // AccessController.doPrivileged(new PrivilegedAction!(Void)() { 132 // override 133 // Void run() { 134 // thread.setContextClassLoader(EvictorThreadFactory.class.getClassLoader()); 135 // return null; 136 // } 137 // }); 138 139 return thread; 140 } 141 } 142 }