Как я должен собирать данные из БД, используя 2 потока? - PullRequest
0 голосов
/ 13 февраля 2019

У меня есть БД с примерно 1600+ записями, все записи читаются медленно, поэтому у меня возникла идея использовать 2 потока для получения данных.У меня есть следующие функции, но я не чувствую, что это быстрее ...

private ArrayList<Worker> getWorkersOnMultipleThread() throws InterruptedException {
    ArrayList<Worker> totalWorkers = new ArrayList<>();
    ArrayList<Worker> totalWorkers2 = new ArrayList<>();
    int total = db.getNumberOfWorkers();
    int firstHalf, secondHalf;
    firstHalf = total / 2;
    if (total % 2 == 1) {
        secondHalf = total / 2 + 1;
    } else {
        secondHalf = total / 2;
    }

    Thread t1 = new Thread() {
        @Override
        public void run() {
            ArrayList<Worker> w1 = db.getHalfOfTheWorkers(firstHalf, true);
            totalWorkers.addAll(w1);
        }
    };

    Thread t2 = new Thread() {
        @Override
        public void run() {
            ArrayList<Worker> w2 = db.getHalfOfTheWorkers(secondHalf, false);
            totalWorkers2.addAll(w2);
        }
    };

    t1.start();
    t1.join();
    t2.start();
    t2.join();

    totalWorkers.addAll(totalWorkers2);

    return totalWorkers;
}

@Override
public ArrayList<Worker> getHalfOfTheWorkers(int limit, Boolean firstHalf) {
    String sql;
    ArrayList<Worker> workers = new ArrayList<>();
    if (firstHalf) {
        sql = "SELECT * FROM NAMES ORDER BY ID FETCH NEXT " + limit + " ROWS ONLY";
    } else {
        sql = "SELECT * FROM NAMES ORDER BY ID OFFSET " + limit + " ROWS";
    }
    try {
        ResultSet rs = statement.executeQuery(sql);
        while (rs.next()) {
            String name = rs.getString("name");
            int id = rs.getInt("id");
            workers.add(new Worker(id, name));
        }
    } catch (Exception ex) {

    }
    return workers;
}

Моя идея состояла в том, чтобы получить первые 50% записей в первом потоке, а вторые 50% во второмнить и, надеюсь, половину времени нужно для получения всех записейКажется, он не работает (я имею в виду, что он не выдает ошибку и прочее и имеет ту же скорость ...)

Main:

@Override
public void initialize(URL url, ResourceBundle rb) {
    ArrayList<Worker> totalWorkers = new ArrayList<>();
    try {
        totalWorkers = getWorkersOnMultipleThread();
        System.out.println(totalWorkers.size());
    } catch (InterruptedException ex) {
        Logger.getLogger(Controller.class.getName()).log(Level.SEVERE, null, ex);
    }
}

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Ваше узкое место не в обработке 1600 строк - это просто слишком мало записей для беспокойства, небольшие записи.Ваша проблема, скорее всего, что-то вроде времени, необходимого для разогрева нового соединения для запроса (в этом случае использование 2-х холодных соединений параллельно не спасет вас).

Посмотрите на пул соединенийсервис, такой как C3P0, DBCP или HikariCP и просто сделать одну выборку.

0 голосов
/ 13 февраля 2019

Это происходит потому, что вы запускаете потоки последовательно, то есть, когда t1 запускается, главный находится в состоянии ожидания, так как вы использовали t1.join().Поток t2 не запускается до тех пор, пока не завершится выполнение потока t1.

t1.start();
t1.join(); //main waiting
t2.start();
t2.join();

Таким образом, вам необходимо изменить порядок:

t1.start();
t2.start();
t1.join(); //main waiting
t2.join();

Таким образом, оба потокаt1 и t2 будут запущены параллельно, и вы дадите команду main дождаться завершения выполнения t1 и t2.

В идеале statement объект не должен быть общим для потоков,Вы должны получать Connection объект на поток из пула потоков.

Поскольку вы используете Apache derby, руководство разработчика не рекомендует использовать соединение .

.
  • Избегайте совместного использования операторов (и их наборов результатов) между потоками.Каждый раз, когда поток выполняет оператор, он должен обрабатывать результаты перед тем, как прекратить соединение.
  • Каждый раз, когда поток получает доступ к соединению, он должен последовательно фиксировать или нет, в зависимости от протокола приложения.
  • Один поток должен быть «управляющим» потоком Соединения с базой данных, который должен обрабатывать задачи более высокого уровня, такие как установление
    Соединения, фиксация, откат, изменение свойств Соединения
    , таких как автоматическая фиксация, закрытие Соединения,завершение работы базы данных
    (во встроенной среде) и т. д.
  • Закрытие наборов результатов и операторов, которые больше не нужны для освобождения ресурсов.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...