【问题标题】:java: Close connection after all threads have terminatedjava:所有线程终止后关闭连接
【发布时间】:2011-01-31 04:28:08
【问题描述】:

以下是我的班级代码

import java.net.*;
import java.util.*;
import java.sql.*;
import org.apache.log4j.*;
class Database {
    private Connection conn;
    private org.apache.log4j.Logger log ;
    private static Database dd=new Database();
    private Database(){
        try{
            log= Logger.getLogger(Database.class);
            Class.forName("com.mysql.jdbc.Driver");
            conn=DriverManager.getConnection("jdbc:mysql://localhost/bc","root","root");
            conn.setReadOnly(false);
            conn.setAutoCommit(false);
            log.info("Datbase created");
            /*Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
            conn=DriverManager.getConnection("jdbc:odbc:rmldsn");
            conn.setReadOnly(false);
            conn.setAutoCommit(false);*/

        }
        catch(Exception e){
            log.info("Cant Create Connection");
        }
    }
    public static Database getDatabase(){
        return dd;
    }
    public Connection getConnection(){
        return conn;
    }
    @Override
    protected void finalize()throws Throwable {
        try{
        conn.close();
        Runtime.getRuntime().gc();
        log.info("Database Close");
        }
        catch(Exception e){
            log.info("Cannot be closed Database");
        }
        finally{
            super.finalize();
        }        
    }
}

这只能通过 getDatabase() 方法来初始化数据库对象。下面是使用单个数据库连接进行 4 个线程的程序。

public class Main extends Thread {
    public static int c=0;
    public static int start,end;
    private int lstart,lend;
    public static Connection conn;
    public static Database dbase;
    public Statement stmt,stmtEXE; public ResultSet rst;
    /**
     * @param args the command line arguments
     */
    static{        
        dbase=Database.getDatabase();
        conn=dbase.getConnection();
    }
    Main(String s){
        super(s);
        try{
        stmt=conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
                                      ResultSet.CONCUR_UPDATABLE);
       start=end;
       lstart=start;
       end=end+5;
       lend=end;
        System.out.println("Start -" +lstart +" End-"+lend);
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void run(){
       try{

            URL url=new URL("http://localhost:8084/TestWeb/");


    rst=stmt.executeQuery("SELECT * FROM bc.cdr_calltimestamp limit "+lstart+","+lend);

        while(rst.next()){

        try{
            rst.updateInt(2, 1);
            rst.updateRow();
            conn.commit();
            HttpURLConnection httpconn=(HttpURLConnection) url.openConnection();
            httpconn.setDoInput(true);
            httpconn.setDoOutput(true);
            httpconn.setRequestProperty("Content-Type", "text/xml");
            //httpconn.connect();

            String reqstring="<?xml version=\"1.0\" encoding=\"US-ASCII\"?>"+
                "<message><sms type=\"mt\"><destination messageid=\"PS0\"><address><number" +
                "type=\"international\">"+ rst.getString(1) +"</number></address></destination><source><address>" +
                "<number type=\"unknown\"/></address></source><rsr type=\"success_failure\"/><ud" +
                "type=\"text\">Hello World</ud></sms></message>";
            httpconn.getOutputStream().write(reqstring.getBytes(), 0, reqstring.length());

            byte b[]=new byte[httpconn.getInputStream().available()];
            //System.out.println(httpconn.getContentType());
            httpconn.getInputStream().read(b);
            System.out.println(Thread.currentThread().getName()+new String(" Request"+rst.getString(1)));
            //System.out.println(new String(b));
            httpconn.disconnect();
            Thread.sleep(100);

            }
         catch(Exception e){
            e.printStackTrace();
        }

       }
            System.out.println(Thread.currentThread().getName()+"  "+new java.util.Date());
       }
       catch(Exception e){
           e.printStackTrace();
       }

    }

    public static void main(String[] args) throws Exception{
       System.out.println(new java.util.Date());
       System.out.println("Memory-before "+Runtime.getRuntime().freeMemory());
        Thread t1=new Main("T1-");
        Thread t2=new Main("T2-");
        Thread t3=new Main("T3-");
        Thread t4=new Main("T4-");
        t1.start();
        t2.start();
        t3.start();
        t4.start();

        System.out.println("Memory-after "+Runtime.getRuntime().freeMemory());


    }

}

我需要在所有线程执行完毕后关闭连接。有什么好主意吗。请帮助我完成这项工作。

【问题讨论】:

  • 我更改了您的问题标题,因为问题与最终确定无关。
  • 旁注:请永远,永远处理这样的异常。至少在您的异常处理程序中打印堆栈跟踪。否则无法排除错误。我意识到这可能只是家庭作业,但不要养成这个习惯!

标签: java methods call finalize


【解决方案1】:

您可以使用Runtime.addShutdownHook() 注册应在 JVM 关闭之前运行的代码。

【讨论】:

  • 这可能是个有问题的想法。引用 API 文档:“关闭挂钩在虚拟机生命周期的一个微妙时刻运行,因此应该进行防御性编码。[...]”。在退出 main 之前进行清理可能更安全(并且可以跨不同的 JVM 移植)。另外,如果你以后将你的东西合并到一个更大的程序中,你就不能再使用关闭钩子了......
  • @sleske:我基本同意,但正确使用关闭挂钩会非常有用。此外,“退出 main”并不一定意味着“结束程序”。
【解决方案2】:

要在所有线程退出后关闭连接,您必须等待所有线程终止。

您可以使用Thread.join() 来等待线程。您必须为每个线程(一个接一个)执行此操作。另外,你必须赶上InterruptedException

【讨论】:

  • 你能用上面的例子告诉我如何使用 Thread.join 吗?
  • 该解决方案实际上取决于“所有线程”的定义,除非您使用 Joachim 提出的解决方案,否则执行的代码仍将在实时用户(而不是 VM)线程中。
  • @M.Jessup:是的,清理将在常规主线程中运行。你认为这是一个问题吗?当然,程序需要知道它的所有线程;毕竟它创造了它们:-)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-11
  • 2020-05-29
  • 2010-11-15
  • 1970-01-01
  • 1970-01-01
  • 2015-08-02
相关资源
最近更新 更多