我想在注销jdbc驱动程序后通过调用方法来关闭线程。
public class CleanupContextListener implements ServletContextListener{
boolean driverDeregisterFlag = false;
public void contextInitialized(ServletContextEvent servletContextEvent) {
//To change body of implemented methods use File | Settings | File Templates.
}
public void contextDestroyed(ServletContextEvent servletContextEvent) {
Enumeration<Driver> drivers = DriverManager.getDrivers();
while(drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
ClassLoader driverClassLoader = driver.getClass().getClassLoader();
ClassLoader thisClassLoader = this.getClass().getClassLoader();
if (driverClassLoader != null && thisClassLoader != null && driverClassLoader.equals(thisClassLoader)) {
try {
DriverManager.deregisterDriver(driver);
driverDeregisterFlag = true;
} catch (SQLException e) {
e.printStackTrace();
}
}
}
if (driverDeregisterFlag) {
ConfigManager.stopCurrentThread();
}
}
}
如您所见,我正在尝试调用ConfigManager.stopCurrentThread()并停止当前线程。
ConfigManager是实现Runnable的类。
stopCurrentThread()在ConfigManager中定义为空方法。
我想在stopCurrentThread()中放入一些代码,然后关闭ConfigManager中的线程。
我怎样才能做到这一点?
最佳答案
这是我的代码的片段,正在解决类似的问题。在c3p0 pool + tomcat 8上进行了测试,但是您可能可以根据需要对其进行修改。
/**
* Destroying application context. We need to safely stop exporting thread
* and do cleanup.
*
* @param arg0
* reason for cleanup
*/
@Override
public void contextDestroyed(@NotNull ServletContextEvent arg0) {
// Safely stop exporting service and shut down the application context
super.contextDestroyed(arg0);
// Close all JDBC connections
C3P0Registry.getNumPooledDataSources();
Iterator<?> it = C3P0Registry.getPooledDataSources().iterator();
while (it.hasNext()) {
try {
PooledDataSource dataSource = (PooledDataSource) it.next();
dataSource.close();
} catch (Exception e) {
log.error("Error when closing connections ...", e);
}
}
// This manually unregisters JDBC drivers, which prevents Tomcat 7 from
// complaining about memory leaks with this class
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
try {
DriverManager.deregisterDriver(driver);
log.info(String.format("Unregistering jdbc driver: %s", driver));
} catch (SQLException e) {
log.error(
String.format("Error deregistering driver %s", driver),
e);
}
}
// Waiting for daemon close() c3p0 jdbc pool thread
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (Thread th : threadSet) {
if (th.isDaemon()) {
try {
if (th.getName().equals(
"Resource Destroyer in BasicResourcePool.close()")) {
th.join();
}
} catch (Exception ex) {
log.info("Shutdown waiting was interrupted ...");
}
}
}
// Clear all thread local variables, this prevents Tomcat 7 from
// complaining about memory leaks
immolate();
}
/**
* Cleanup function which cleans all thread local variables. Using thread
* local variables is not a good practice but unfortunately some libraries
* are still using them. We need to clean them up to prevent memory leaks.
*
* @return number of Thread local variables
*/
private int immolate() {
int count = 0;
try {
final Field threadLocalsField = Thread.class
.getDeclaredField("threadLocals");
threadLocalsField.setAccessible(true);
final Field inheritableThreadLocalsField = Thread.class
.getDeclaredField("inheritableThreadLocals");
inheritableThreadLocalsField.setAccessible(true);
for (final Thread thread : Thread.getAllStackTraces().keySet()) {
count += clear(threadLocalsField.get(thread));
count += clear(inheritableThreadLocalsField.get(thread));
}
log.info("Immolated " + count + " values in ThreadLocals");
} catch (Exception e) {
log.error("ThreadLocalImmolater.immolate()", e);
}
return count;
}
/**
* Cleaner for thread local map.
*
* @param threadLocalMap
* thread local map to clean or null
* @return number of cleaned objects
* @throws Exception
* in case of error
*/
private int clear(@NotNull final Object threadLocalMap) throws Exception {
if (threadLocalMap == null) {
return 0;
}
int count = 0;
final Field tableField = threadLocalMap.getClass().getDeclaredField(
"table");
tableField.setAccessible(true);
final Object table = tableField.get(threadLocalMap);
for (int i = 0, length = Array.getLength(table); i < length; ++i) {
final Object entry = Array.get(table, i);
if (entry != null) {
final Object threadLocal = ((WeakReference<?>) entry).get();
if (threadLocal != null) {
log(i, threadLocal);
Array.set(table, i, null);
++count;
}
}
}
return count;
}