当您从Tomcat 8.0.33服务器中删除Web应用程序时,如何真正知道线程是被杀死还是保持运行?

如何解决当您从Tomcat 8.0.33服务器中删除Web应用程序时,如何真正知道线程是被杀死还是保持运行?

我有一个监听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 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-