为什么单个线程使我的Java程序更快?

时间:2011-07-13 00:20:28

标签: java sql multithreading performance

我的任务是创建一个sql数据库并在Java中创建一个GUI来访问它。我几乎拥有它,但我有一个关于线程的问题。在今天之前,我没有在我的程序中使用任何线程,因此只是从数据库中提取150条记录,我不得不等待大约5-10秒。这非常不方便,我不确定我是否可以解决这个问题。今天我在网上看到在类似我的程序中使用线程,我决定在这个方法中使用一个线程:

public Vector VectorizeView(final String viewName) {
    final Vector table = new Vector();
    int cCount = 0;
    try {
        cCount = getColumnCount(viewName);
    } catch (SQLException e1) {
        e1.printStackTrace();
    }
    final int viewNameCount = cCount;

    Thread runner = new Thread(){

        public void run(){
            try {
                Connection connection = DriverManager.getConnection(getUrl(),
                        getUser(), getPassword());
                Statement statement = connection.createStatement();
                ResultSet result = statement.executeQuery("Select * FROM "
                        + viewName);
                while (result.next()) {
                    Vector row = new Vector();
                    for (int i = 1; i <= viewNameCount; i++) {
                        String resultString = result.getString(i);
                        if (result.wasNull()) {
                            resultString = "NULL";
                        } else {
                            resultString = result.getString(i);
                        }
                        row.addElement(resultString);

                    }
                    table.addElement(row);
                }
            } catch (SQLException e) {

                e.printStackTrace();
            }
        }
    };
    runner.start();
    return table;

}

我唯一真正改变的是添加线程'runner'并且性能呈指数级增长。通过这种方式几乎可以立即发出500条记录。

该方法之前看起来像这样:

public Vector VectorizeTable(String tableName) {

    Vector<Vector> table = new Vector<Vector>();
    try {
        Connection connection = DriverManager.getConnection(getUrl(),
                getUser(), getPassword());
        Statement statement = connection.createStatement();
        ResultSet result = statement.executeQuery("Select * FROM "
                + tableName);
        while (result.next()) {
            Vector row = new Vector();
            for (int i = 1; i <= this.getColumnCount(tableName); i++) {
                String resultString = result.getString(i);
                if (result.wasNull()) {
                    resultString = "NULL";
                } else {
                    resultString = result.getString(i);
                }
                row.addElement(resultString);

            }
            table.addElement(row);
        }
    } catch (SQLException e) {

        e.printStackTrace();
    }
    return table;
}

我的问题是为什么线程的方法比没有线程的方法快得多?我在程序中的任何地方都不使用多个线程。我看过网上但似乎没有回答我的问题。

任何人都可以提供的任何信息都将不胜感激。我是线程XO上的菜鸟

如果您需要任何其他信息以帮助了解正在发生的事情,请告诉我们!

答案:

看看Aaron的回答这根本不是线程的问题。我现在觉得很无礼:(。感谢@Aaron!

4 个答案:

答案 0 :(得分:3)

我认为您正在做的是出现以使数据库加载更快,因为VectorizeView方法在数据加载之前返回。然后负载在后台进行,并在(可能)与之前相同的时间内完成。

您可以在thread.join()来电后添​​加thread.start()来调试此理论。


如果发生了这种情况,您可能需要做一些事情来阻止应用程序的其他部分在加载完成之前访问table对象。否则,如果用户在发布后过早做某事,您的应用程序可能会出现错误行为。


FWIW,从数据库加载100或500条记录应该很快,除非查询本身对数据库来说很昂贵。对于从表中进行简单选择,情况不应该如此......除非您实际上是从视图而不是表中进行选择,并且视图设计不当。无论哪种方式,你可能会更好地关注为什么这么简单的查询需要这么长时间,而不是试图在一个单独的线程中运行它。


在您的跟进中,您说join之后start的版本与没有它的版本一样快。

我的第一反应是说:“将join留在那里。你已经解决了问题。”

但这并不能解释实际发生的事情。而我现在完全感到困惑。我能想到的最好的是你的应用程序正在做什么之前当前线程上的这个是它的原因。

也许你应该调查应用程序在发生这种情况的过程中正在做什么。看看你是否可以找出所有时间花在哪里。

  • 进行线程转储并查看线程。
  • 在调试器下运行它以查看“暂停”发生的位置。
  • 简介。
  • 将应用程序日志记录设置为较高级别,并查看是否有任何线索。
  • 检查数据库日志。
  • 诸如此类

答案 1 :(得分:2)

看起来你开始(即start)后台线程来执行查询,但你没有join等待计算完成。当您返回table时,它将不会填充查询结果 - 另一个线程会在您的方法返回后随时间填充。该方法几乎立即返回,因为它没有真正的工作。

如果要确保在方法返回之前加载数据,则需要调用runner.join()。如果你这样做,你会发现加载数据的时间与以前一样长。与新代码的唯一区别在于,工作在单独的执行线程中执行,允许其余代码继续执行其需要执行的其他工作。请注意,如果主线程中的代码在后台线程实际填充之前尝试使用Vector中的数据,则无法调用join可能会导致错误。

更新:我刚刚注意到您还在多线程版本中预先计算getColumnCount,而在单线程版本中,您为每次迭代计算它内循环。取决于该方法的复杂性,这可能解释部分加速(如果有的话)。

答案 2 :(得分:1)

你确定它更快吗?由于您启动了单独的线程,因此您将立即返回table。但是,您确定在完全填充数据后测量时间吗?


更新 要正确测量时间,请在某处保存runner对象并致电runner.join()。您甚至可以使用相同的方法进行测试。

答案 3 :(得分:0)

好的,我认为如果你在这个方法结束时检查table,你会发现它是空的。那是因为start开始在后台运行线程,并且您立即返回表,而后台线程没有机会填充它。所以它看起来更快,但事实并非如此。