powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Проблема с ConcurrentHashMap
25 сообщений из 99, страница 1 из 4
Проблема с ConcurrentHashMap
    #38520610
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Такая проблема. ConcurrentHashMap<Integer, Session> теряет элементы. Дело в том, что с ним работает несколько потоков, какие-то пишут, какие-то читают, а какие-то удаляют элементы. В качестве ключа выступает id сессии из БД. Ключ уникален(автоинкриментное поле). При удалении так же удаляется запись из БД. Но вот проблема! По истечении некоторого времени, по неизвестной причине сессия сохраняется(запись в БД и само подключение клиента), а в HashMap его уже нет. В чем может быть проблема? Спасибо!
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520628
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Проблема в том что ConcurrentHashMap никак не участвует в транзакции на уровне БД. Поэтому очевидно, что так просто гарантировать консистентность состояние в БД и ConcurrentHashMap нельзя. Тем более в многопоточной среде.
Для начала можно релизовать логирование чтобы точно знать что когда и куда записано и удалено.
Вероятность того что ConcurrentHashMap сама по себе что-то там теряет очень мала.
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520636
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczПроблема в том что ConcurrentHashMap никак не участвует в транзакции на уровне БД. Поэтому очевидно, что так просто гарантировать консистентность состояние в БД и ConcurrentHashMap нельзя. Тем более в многопоточной среде.
Для начала можно релизовать логирование чтобы точно знать что когда и куда записано и удалено.
Вероятность того что ConcurrentHashMap сама по себе что-то там теряет очень мала.

Я понимаю и поэтому делаю так:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
private void removeSession() { Connection mConnection = null; Statement mStatement = null; try { try { if (sessionType != SessionType.Unknown) { mConnection = getConnection(); mConnection.setAutoCommit(false); } if (sessionType == SessionType.Client) { mStatement = mConnection.createStatement(); mStatement.executeUpdate(String.format("DELETE FROM users_connections WHERE session_id=%s",getSessionId())); mStatement.executeUpdate(String.format("UPDATE connections_log SET disconnect_date_time=NOW() WHERE id=%s",getLogId())); mStatement.executeUpdate(String.format("UPDATE hosts_online SET host_busy=%s WHERE host_id=%s",0, getPartner().getHostId())); mConnection.commit(); getPartner().setPeerToPeer(false); getPartner().sendData(new Packets.Disconnected()); getPartner().setPartner(null); notifyUsers(getPartner().getHostId()); } else if (sessionType == SessionType.Host) { mStatement = mConnection.createStatement(); mStatement.executeUpdate(String.format("DELETE FROM hosts_online WHERE host_id=%s",getHostId())); mStatement.executeUpdate(String.format("UPDATE connections_log SET disconnect_date_time=NOW() WHERE id=%s",getLogId())); mConnection.commit(); if (getPartner() != null) { getPartner().killSession(); } notifyUsers(getHostId()); Hub.HOSTS_SESSIONS.remove(getHostId()); } else if (sessionType == SessionType.User) { mStatement = mConnection.createStatement(); mStatement.executeUpdate(String.format("DELETE FROM users_online WHERE user_session_id=%s",getSessionId())); mConnection.commit(); Hub.USERS_SESSIONS.remove(getSessionId()); } } catch (SQLException e) { LogHelper.logError(e, "removeSession"); if (mConnection != null) {mConnection.rollback();} } } catch (Exception e) { LogHelper.logError(e, "removeSession"); } finally { Hub.SESSONS_COUNT--; try { if (mConnection != null) {mConnection.close();} if (mStatement != null) {mStatement.close();} } catch (SQLException e) { LogHelper.logError(e, "removeSession"); } } }

...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520640
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Более того при выполнении метода LogHelper.logError, мне еще и письмо приходит на мыло. Но дело в том, что этого не происходит... Значит все нормально.
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520648
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Фишка в том, что этот метод removeSession вызывается при потере подключения Socket:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
try {
			int receivedBytes=0;
			byte[] dataBuffer = new byte[Hub.SESSION_BUFFER_SIZE];
			InputStream stream=mClientSocket.getInputStream();
			
			//Пока данные есть...
			while ((receivedBytes = stream.read(dataBuffer, 0, dataBuffer.length)) != -1) {
				if(!isPeerToPeer()){
					mPacketSplitter.splitData(dataBuffer, receivedBytes);
				}
				else{
					getPartner().sendRawData(dataBuffer, receivedBytes);
				}
			}

			removeSession();
		}catch (Exception e) {
			removeSession();
		}
		finally{
			try {
				mClientSocket.close();
			} catch (IOException e) {
				System.out.println(String.format("ERROR CLOSE! ID =%s",getHostId()));
				e.printStackTrace();
			}
		}




Но при этом клиент может взаимодействовать с системой. Т.е соединение точно есть. Но из HOSTS_SESSIONS пропадает. Т.е get по ключу возвращает null
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520663
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сделайте меня это развидеть, пожалуйста.
Полиморфизм? Первый раз слышу! Нужен ещё один SessionType? Не беда - скопипастим ещё один if блок.
SQL Injection/binding variables/query cache... Да, ну это всё.
Extract variable. Это где такое?
Логирование? Только для ошибок. Если нет Exception-а, значит всё нормально и логировать незачем.
Hub.SESSONS_COUNT--. В многопоточной системе? Really?
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520675
cdtyjv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GorloPavel ,
Ну как вам уже ответили, вероятность того, что это баг в ConcurrentHashMap, стремиться к нулю. А вот вероятность того, что это гонка у вас в коде, примерно 99,999%. Где именно сидит эта гонка мы не знаем, и знать не можем, так как вы нам показали только одно из мест, где идет работа с этой мапкой.
Но в целом ваш код выглядит очень плохо с точки зрения многопоточности, и я даже с достаточно высокой вероятностью могу предположить следующее:
1) В методе removeSession вы сначала удаляете из базы, а потом удаляете из мапки (это мы видим в том коде, что вы дали).
2) А в методe addSession (или как он у вас называется?) вы сначала пишете в базу, а потом пишете в мапку.
3) Теперь следите за руками, поток 1 вызывает removeSession, поток 2 вызывает addSession, и так получается, что эти операции выполняются в следующем порядке:
Поток 2: создать сессию;
Поток 1: удалить сессию;
Поток 1: Hub.USERS_SESSIONS.remove(id);
Поток 2: Hub.USERS_SESSIONS.put(id, ...).

Все, сессии в базе нет, а в мапке есть.
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520676
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz,

Я конечно понимаю. Но опыт приходит со временем. Если можно, то покажите как правильно. На самом деле String.format для запросов только в этом месте программы. Так везде CallableStatement или PreparedStatement. Hub.SESSONS_COUNT-- как ни странно работает нормально :)
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520683
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cdtyjv,
Сессию удалить может только сам поток сессии и put вызывает он же.
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520697
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GorloPavelЯ конечно понимаю. Но опыт приходит со временем.

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

GorloPavelЕсли можно, то покажите как правильно.
Правильно писать короткие методы. Чтобы не вываливать простыню на форум, а четко понимать в каком методе может быть проблема.
Правильно заменять if\else на полиморфизм, особенно если блоки схожие, то выносить общий код.
Правильно использовать переменные а не вызывать один и тот же метод 4 раза подряд.
Правильно писать понятный самодокументируемый код а не вводить читателя в ступор вот такими пируэтами:
getPartner().setPartner(null);
Правильно держать SQL запросы вне Java кода, либо использовать Query DSL.
Правильно разбирвать проект на абстрактные слои, а не запускать SQL запросы откуда вздумается.
Правильно использовать binding variable для параметров SQL запроса.
Правильно логировать все изменения состояния с разным уровнем логирования, а не только Exception-ы.
Правильно использовать фреймверки логирования, а не LogHelper, который везде вызывается, так что даже не понятно кто писал в лог.

GorloPavelHub.SESSONS_COUNT-- как ни странно работает нормально :)
Правильно изучить многопоточность и атомарные операции, прежде чем пытаться написать что-то пригодное для использования в многопоточной среде.
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520699
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GorloPavelcdtyjv,
Сессию удалить может только сам поток сессии и put вызывает он же.
Логируете все операции с session id и тогда по логу будет видно что происходило и почему для конкретного session id, который вы обнаруили в БД.
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520727
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz,

Спасибо за ответы. Замечания приняты. Но я все равно не пойму куда могут деться сессии из мапа в этом коде, если put и remove может выполнять только сам поток сессии. Логировать сейчас что-то очень проблемно. Сервис работает и его используют тысячи пользователей. Я просто погрязну в логах на вечно. Может все таки сделать так как вы посоветовали в моей предыдущей теме? Хотелось бы увидеть пример от гуру :)
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520731
cdtyjv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GorloPavel ,
Что такое "сам поток сессии"? Например, у вас 1000 сессий. Что, к каждой постоянно привязан какой-то поток один единственный поток?
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520736
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GorloPavel,

Не понятно как используется SESSONS_COUNT.
Не понятно как вы локализовали проблему в removeSession. Почему другие методы исключены?
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520737
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cdtyjv,

Это поток(Thread) сокета. В нем обрабатываются данные от клиента и к примеру при авторизации эта сессия добавляется в HashMap. При потере соединения сессия должна удалить себя из HashMap и БД.
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520738
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
cdtyjv,

Это поток(Thread) сокета. В нем обрабатываются данные от клиента и к примеру при авторизации эта сессия добавляется в HashMap. При потере соединения сессия должна удалить себя из HashMap и БД.
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520740
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GorloPavelЯ просто погрязну в логах на вечно.
Зачем в них грязнуть? Пишите в файлы. Храните все файлы за последние несколько дней. Проблема выделить под это дело пару гигабайт HDD?
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520742
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Blazkowicz,

Потому что в других методах нет remove из HashMap. Только в этом методе . В остальных get и put. Про put я уже объяснил, что он тоже в этом потоке. Т.е сессия сама себя добавляет и сама себя удаляет при отключении.
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520743
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GorloPavelЭто поток(Thread) сокета. В нем обрабатываются данные от клиента и к примеру при авторизации эта сессия добавляется в HashMap. При потере соединения сессия должна удалить себя из HashMap и БД.
Бляха-муха. Сокет сервер на коленке. Чем готовые решения не угодили-то?
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520746
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczGorloPavel,
Не понятно как используется SESSONS_COUNT.

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

Вот кстати как я их "порождаю"

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
private class ListenConnections implements Runnable
	{
		public void run() {
			try {
				
				Socket acceptClient = null;
				
				while(true){
					
					acceptClient=mSocketListener.accept();
					
					if(SESSONS_COUNT<SETTINGS.HUB_MAX_CONNECTIONS){
						acceptClient.setSoTimeout(SETTINGS.HUB_TIME_OUT);
						new Thread(new Session(acceptClient,Hub.this)).start();
						SESSONS_COUNT++;
					}else{
						sendData(acceptClient, new Packets.Error(ErrorCodes.SERVER_OVERLOADED));
						acceptClient.close();
					}
					
				}
			}catch(Exception ex){
				ex.printStackTrace();
				if(!mStopServer){
					LogHelper.logError(ex, "ListenConnections");
				}				
			}
		}
	}

...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520749
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczБляха-муха. Сокет сервер на коленке. Чем готовые решения не угодили-то?
Так вышло. Уже ничего не поделать. Надо решать проблему в этом коде.
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520751
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
getSessionId() возвращает final поле?
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520763
GorloPavel
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
BlazkowiczgetSessionId() возвращает final поле?
Оно не меняется нигде. Только задается однажды(из БД) и все. Нет не final.
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520764
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
С каким типом сессий возникает проблема?
...
Рейтинг: 0 / 0
Проблема с ConcurrentHashMap
    #38520765
Фотография Blazkowicz
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
GorloPavelНет не final.
Зря.
...
Рейтинг: 0 / 0
25 сообщений из 99, страница 1 из 4
Форумы / Java [игнор отключен] [закрыт для гостей] / Проблема с ConcurrentHashMap
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]