java—当您从ApacheTomcat8.0.33服务器上删除webapp时,如何真正知道线程是否被终止或继续运行?

wwodge7n  于 2021-07-05  发布在  Java
关注(0)|答案(0)|浏览(245)

我有一个程序,可以收听博士后的活动。应用程序已被证实,工作正常。问题是,当我从服务器上删除应用程序时,我可以看到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");
            }
        }
    }

}

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题