Почему это изменение блокировки так сильно влияет на производительность JDBC? - PullRequest
2 голосов
/ 01 февраля 2012

Я пишу пул соединений с базой данных для использования в большом многопоточном приложении, написанном для целевых стандартов jdk4, с помощью следующего кода я могу запросить базу данных mysql по локальной сети 1000 раз за 0,4 секунды с помощью моего тестового примера.

synchronized(lockA) {
    if(free.size() > 0) {
        c = (Connection) free.removeFirst();
    }

    if(c == null) {
        c = DriverManager.getConnection(query, name, passw);
    }
}

здесь lockA защищает свободный список (LinkedList), он используется там, где список изменен и доступен.Имеет смысл переместить getConnection из этого замка в его собственный защищенный блок.GetConnection должен быть защищен блокировкой, потому что где-то он не является потокобезопасным.

Так что, если я изменю его, DriverManager и список будут защищены отдельными блокировками, например.

synchronized(lockA) {
    if(free.size() > 0) {
        c = (Connection) free.removeFirst();
    }
}

if(c == null) {
    synchronized(lockB) {
        c = DriverManager.getConnection(query, name, passw);
    }
}

Я получаю постоянные пропуски в кеше (C равен нулю), и поэтому производительность снижается, так что выполнение одного и того же запроса, который занимает 0,4 секунды, занимает 4 секунды.

Почему это так?

РЕДАКТИРОВАТЬ:

Я решил эту проблему, проблема возникает из-за способа, которым функциональные блоки создаются при слишком большом количестве соединений.

Это то, что происходило в начале функции.

synchronized(waitLocK) {
    try {
        while(count >= limit) {
            waitLock.wait();
        } 
    } catch (InterruptedException e) {
    }
}

waitLock освобождается при освобождении соединения.Но здесь происходит то, что после блока кода для создания соединения увеличивается переменная count (volatile).

Это привело к открытию шлюзов, потому что, когда 1000 потоков пытались пройти тест ожиданиявсе они прошли, потому что count был все еще 0, а затем перегружен getConnection ().

Перемещение count ++ на значение после попытки решает эту проблему.

1 Ответ

0 голосов
/ 02 февраля 2012

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

При написании параллельного кода на Java у меня есть простое правило:

Если в вашем коде есть ключевое слово synchronized, оно, вероятно, неверно и не удастся скрытым и непредсказуемым образом.

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

Комментарий Скаффмана верен - вы действительно не хотите реализовывать пул соединений. Выберите любую из доступных реализаций.

Допустим, это был не пул соединений. Зачем использовать синхронизацию + LinkedList вместо ConcurrentLinkedQueue? Ваша логика пытается получить соединение из списка; если нет доступного соединения, оно создает новое соединение (которое, по-видимому, вызывающий абонент вернет обратно в список, когда это будет сделано).

Параллелизм Java на практике - фантастическая книга, если вы ее еще не читали.

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