问题描述
我有一个监听postgres事件的程序。该应用程序已解聚,并且可以正常工作。问题是当我从服务器删除应用程序时,我可以在catalina文件中看到日志。看起来线程仍然在后台运行。我应该如何停止正在运行的线程。
catalina中的日志为:
03-Sep-2020 15:41:46.025 INFO [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.startup.HostConfig.undeploy Undeploying context [/msms]
03-Sep-2020 15:41:46.035 WARNING [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [msms] registered the JDBC driver [com.impossibl.postgres.jdbc.PGDriver] but Failed to unregister it when the web application was stopped. To prevent a memory leak,the JDBC Driver has been forcibly unregistered.
03-Sep-2020 15:41:46.036 WARNING [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [msms] appears to have started a thread named [PG-JDBC Housekeeper] but has Failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
java.lang.Object.wait(Native Method)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
com.impossibl.postgres.jdbc.ThreadedHousekeeper$1.run(ThreadedHousekeeper.java:187)
03-Sep-2020 15:41:46.036 WARNING [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [msms] appears to have started a thread named [PG-JDBC I/O (1)] but has Failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
io.netty.channel.epoll.Native.epollWait(Native Method)
io.netty.channel.epoll.Native.epollWait(Native.java:148)
io.netty.channel.epoll.Native.epollWait(Native.java:141)
io.netty.channel.epoll.EpollEventLoop.epollWaitNoTimerChange(EpollEventLoop.java:290)
io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:347)
io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
java.lang.Thread.run(Thread.java:745)
03-Sep-2020 15:41:46.037 SEVERE [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalmapForLeaks The web application [msms] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@24002836]) and a value of type [io.netty.util.internal.InternalThreadLocalmap] (value [io.netty.util.internal.InternalThreadLocalmap@24e9076e]) but Failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
使用以下代码。
/**
* This program uses the pgjdbc_ng driver which has an asynchronous
* implementation for blocking on the Postgres NOTIFY/LISTEN events.
*
* No polling is done using this driver. You will see a forever loop
* "while(true)" in the main(). This is done to keep the program running and
* listening to multiple events happening in Postgres. normally you would just
* take one event and then do something with it.
*
*/
public class ListenNotify {
// Create the queue that will be shared by the producer and consumer
private BlockingQueue queue = new ArrayBlockingQueue(10);
// Database connection
PGConnection connection;
public ListenNotify() {
// Get database info from environment variables
String DBHost = System.getenv("DBHost");
String dbname = System.getenv("dbname");
String DBUserName = System.getenv("DBUserName");
String DBPassword = System.getenv("DBPassword");
// Create the listener callback
PGNotificationListener listener = new PGNotificationListener() {
@Override
public void notification(int processId,String channelName,String payload) {
// Add event and payload to the queue
queue.add("/channels/" + channelName + " " + payload);
System.out.println("*********INSIDE NOTIFICATION*************");
System.out.println("notification = " + payload);
Advocate advocate = ParseJSON.parseJSON(payload);
String sent=advocate.getSent();
String date=advocate.getDate();
String mobile = advocate.getMobile();
String message = advocate.getMessage();
System.out.println("sent::" + sent);
System.out.println("message::" + message);
System.out.println("mobile::" + mobile);
System.out.println("date::" + date);
sendSMS sendSMS = new sendSMS();
Integer ack = sendSMS.sendSMS(mobile,message);
System.out.println("ack::" + ack);
}
};
try {
// Create a data source for logging into the db
PGDataSource dataSource = new PGDataSource();
dataSource.setHost("172.16.2.32");
dataSource.setPort(5432);
dataSource.setDatabaseName("smsdb");
dataSource.setUser("postgres");
dataSource.setPassword("postgres");
// Log into the db
connection = (PGConnection) dataSource.getConnection();
// add the callback listener created earlier to the connection
connection.addNotificationListener(listener);
// Tell Postgres to send NOTIFY q_event to our connection and listener
Statement statement = connection.createStatement();
DatabaseMetaData dbmd = connection.getMetaData();
try (ResultSet tables = dbmd.getTables(null,null,"%",new String[] { "TABLE" })) {
while (tables.next()) {
System.out.println(tables.getString("TABLE_NAME"));
}
}
statement.execute("LISTEN q_event");
statement.close();
} catch (sqlException e) {
e.printstacktrace();
}
}
/**
* @return shared queue
*/
public BlockingQueue getQueue() {
return queue;
}
/**
*
* main entry point
*
* @param args
*/
public static void main(String[] args) {
// Create a new listener
ListenNotify ln = new ListenNotify();
// Get the shared queue
BlockingQueue queue = ln.getQueue();
// Loop forever pulling messages off the queue
while (true) {
try {
// queue blocks until something is placed on it
String msg = (String) queue.take();
// Do something with the event
System.out.println(msg);
} catch (InterruptedException e) {
e.printstacktrace();
}
}
}
}
即使这个类也没有注销驱动程序。此外,这种方法的问题(在上下文侦听器中强制注销)是某些驱动程序维护内部注册状态。这意味着,当侦听器随后将驱动程序从DriverManager中删除驱动程序时,其内部状态认为该驱动程序仍在注册。反过来,这意味着它将在重新加载后无法重新注册。哎呀!
H2和Postgresql是两个类似的驱动程序(链接指向相关的源代码行)。
MyWebAppContextListener.java
import javax.servlet.ServletContextEvent;
import javax.servlet.servletcontextlistener;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.sqlException;
import java.util.Enumeration;
public class MyWebAppContextListener implements servletcontextlistener {
@Override
public void contextinitialized(ServletContextEvent servletContextEvent) {
System.out.println("************** Starting up! **************");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("************** Shutting down! **************");
System.out.println("Destroying Context...");
// ... First close any background tasks which may be using the DB ...
// ... Then close any DB connection pools ...
// Now deregister JDBC drivers in this context's ClassLoader:
// Get the webapp's ClassLoader
ClassLoader cl = Thread.currentThread().getContextClassLoader();
// Loop through all drivers
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
if (driver.getClass().getClassLoader() == cl) {
try {
System.out.println("Deregistering JDBC driver {}");
DriverManager.deregisterDriver(driver);
} catch (sqlException ex) {
System.out.println("Error deregistering JDBC driver {}");
ex.printstacktrace();
}
} else {
// driver was not registered by the webapp's ClassLoader and may be in use elsewhere
System.out
.println("Not deregistering JDBC driver {} as it does not belong to this webapp's ClassLoader");
}
}
}
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)