Почему один поток делает мою Java-программу намного быстрее? - PullRequest
0 голосов
/ 13 июля 2011

Мне было поручено создать базу данных sql и создать графический интерфейс на Java для доступа к нему. У меня в значительной степени есть это, но у меня есть вопрос о темах. До сегодняшнего дня я не использовал никакие потоки в моей программе, и в результате, чтобы просто извлечь 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!

Ответы [ 4 ]

3 голосов
/ 13 июля 2011

Я думаю, что вы делаете , появляющийся , чтобы ускорить загрузку базы данных, потому что метод VectorizeView возвращается до загрузки данных. Затем загрузка продолжается в фоновом режиме и завершается (вероятно) в то же время, что и раньше.

Вы можете проверить эту теорию, добавив вызов thread.join() после вызова thread.start().


Если это именно то, что происходит, вам, вероятно, нужно что-то сделать, чтобы другие части вашего приложения не могли получить доступ к объекту table до завершения загрузки. В противном случае ваше приложение может вести себя некорректно, если пользователь что-то сделает слишком рано после запуска.


FWIW, загрузка 100 или 500 записей из базы данных должна быть быстрой, если сам запрос не является дорогостоящим для базы данных. Это не должно иметь место для простого выбора из таблицы ... если только вы на самом деле не выбираете из представления, а не из таблицы, и представление плохо спроектировано. В любом случае, вам, вероятно, лучше сосредоточиться на том, почему такой простой запрос занимает столько времени, чем пытаться запустить его в отдельном потоке.


В своем выступлении вы говорите, что версия с join после start такая же быстрая, как и без нее.

Моя первая реакция - сказать: "Оставьте join там. Вы устранили проблему."

Но это не объясняет, что на самом деле происходит. И теперь я совершенно сбит с толку. Лучшее, что я могу придумать, это то, что ваше приложение делает до , это в текущей нити является причиной этого.

Возможно, вам следует выяснить, что приложение делает в период, когда это происходит. Посмотри, сможешь ли ты выяснить, где все время тратится.

  • Возьми дамп нити и посмотри на нити.
  • Запустите его под отладчиком, чтобы увидеть, где происходит «пауза».
  • Профиль.
  • Установите ведение журнала приложения на высокий уровень и посмотрите, есть ли какие-либо подсказки.
  • Проверьте журналы базы данных.
  • Etcetera
2 голосов
/ 13 июля 2011

Похоже, что вы запускаете (то есть start) фоновый поток для выполнения запроса, но вы не join ожидаете завершения вычислений.Когда вы возвращаете table, он еще не будет заполнен результатами запроса - другой поток заполнит его через некоторое время, после того, как ваш метод вернет .Метод возвращается практически мгновенно, потому что он не выполняет никакой реальной работы.

Если вы хотите убедиться, что данные загружены до возврата метода, вам нужно вызвать runner.join().Если вы сделаете это, вы увидите, что загрузка данных занимает столько же времени, сколько и раньше.Единственная разница с новым кодом заключается в том, что работа выполняется в отдельном потоке выполнения, что позволяет остальной части кода выполнять другую работу, которую он должен выполнить.Обратите внимание, что неудачный вызов join может привести к ошибкам, если код в вашем основном потоке пытается использовать данные в векторе до того, как он будет фактически заполнен фоновым потоком.

Обновление: Я только что заметил, что вы также предварительно вычисляете getColumnCount в многопоточной версии, в то время как в однопоточной версии вы вычисляете ее для каждой итерации внутреннего цикла.В зависимости от сложности этого метода это может объяснить часть ускорения (если оно есть).

1 голос
/ 13 июля 2011

Вы уверены, что это быстрее? Поскольку вы запускаете отдельную ветку, вы немедленно вернете table. Но вы уверены, что измеряете время после того, как оно полностью заполнено данными?


Обновление Чтобы правильно измерить время, сохраните runner объект где-нибудь и вызовите runner.join(). Вы можете даже к нему в том же методе для тестирования.

0 голосов
/ 13 июля 2011

Хорошо, я думаю, что если вы изучите table в конце этого метода, вы обнаружите, что он пуст.Это связано с тем, что start запускает поток в фоновом режиме, и вы немедленно возвращаете таблицу, если фоновый поток не имеет возможности ее заполнить.Так что, похоже, идет быстрее, но на самом деле это не так.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...