Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Java [игнор отключен] [закрыт для гостей] / Проблема с ConcurrentHashMap / 25 сообщений из 99, страница 1 из 4
09.01.2014, 15:43
    #38520610
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема с ConcurrentHashMap
Такая проблема. ConcurrentHashMap<Integer, Session> теряет элементы. Дело в том, что с ним работает несколько потоков, какие-то пишут, какие-то читают, а какие-то удаляют элементы. В качестве ключа выступает id сессии из БД. Ключ уникален(автоинкриментное поле). При удалении так же удаляется запись из БД. Но вот проблема! По истечении некоторого времени, по неизвестной причине сессия сохраняется(запись в БД и само подключение клиента), а в HashMap его уже нет. В чем может быть проблема? Спасибо!
...
Рейтинг: 0 / 0
09.01.2014, 15:52
    #38520628
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема с ConcurrentHashMap
Проблема в том что ConcurrentHashMap никак не участвует в транзакции на уровне БД. Поэтому очевидно, что так просто гарантировать консистентность состояние в БД и ConcurrentHashMap нельзя. Тем более в многопоточной среде.
Для начала можно релизовать логирование чтобы точно знать что когда и куда записано и удалено.
Вероятность того что ConcurrentHashMap сама по себе что-то там теряет очень мала.
...
Рейтинг: 0 / 0
09.01.2014, 16:00
    #38520636
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема с ConcurrentHashMap
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
09.01.2014, 16:01
    #38520640
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема с ConcurrentHashMap
Более того при выполнении метода LogHelper.logError, мне еще и письмо приходит на мыло. Но дело в том, что этого не происходит... Значит все нормально.
...
Рейтинг: 0 / 0
09.01.2014, 16:05
    #38520648
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема с ConcurrentHashMap
Фишка в том, что этот метод 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
09.01.2014, 16:13
    #38520663
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема с ConcurrentHashMap
Сделайте меня это развидеть, пожалуйста.
Полиморфизм? Первый раз слышу! Нужен ещё один SessionType? Не беда - скопипастим ещё один if блок.
SQL Injection/binding variables/query cache... Да, ну это всё.
Extract variable. Это где такое?
Логирование? Только для ошибок. Если нет Exception-а, значит всё нормально и логировать незачем.
Hub.SESSONS_COUNT--. В многопоточной системе? Really?
...
Рейтинг: 0 / 0
09.01.2014, 16:19
    #38520675
cdtyjv
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема с ConcurrentHashMap
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
09.01.2014, 16:19
    #38520676
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема с ConcurrentHashMap
Blazkowicz,

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

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

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

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

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

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

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

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

Потому что в других методах нет remove из HashMap. Только в этом методе . В остальных get и put. Про put я уже объяснил, что он тоже в этом потоке. Т.е сессия сама себя добавляет и сама себя удаляет при отключении.
...
Рейтинг: 0 / 0
09.01.2014, 16:54
    #38520743
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема с ConcurrentHashMap
GorloPavelЭто поток(Thread) сокета. В нем обрабатываются данные от клиента и к примеру при авторизации эта сессия добавляется в HashMap. При потере соединения сессия должна удалить себя из HashMap и БД.
Бляха-муха. Сокет сервер на коленке. Чем готовые решения не угодили-то?
...
Рейтинг: 0 / 0
09.01.2014, 16:56
    #38520746
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема с ConcurrentHashMap
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
09.01.2014, 16:59
    #38520749
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема с ConcurrentHashMap
BlazkowiczБляха-муха. Сокет сервер на коленке. Чем готовые решения не угодили-то?
Так вышло. Уже ничего не поделать. Надо решать проблему в этом коде.
...
Рейтинг: 0 / 0
09.01.2014, 16:59
    #38520751
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема с ConcurrentHashMap
getSessionId() возвращает final поле?
...
Рейтинг: 0 / 0
09.01.2014, 17:03
    #38520763
GorloPavel
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема с ConcurrentHashMap
BlazkowiczgetSessionId() возвращает final поле?
Оно не меняется нигде. Только задается однажды(из БД) и все. Нет не final.
...
Рейтинг: 0 / 0
09.01.2014, 17:03
    #38520764
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема с ConcurrentHashMap
С каким типом сессий возникает проблема?
...
Рейтинг: 0 / 0
09.01.2014, 17:04
    #38520765
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Проблема с ConcurrentHashMap
GorloPavelНет не final.
Зря.
...
Рейтинг: 0 / 0
Форумы / Java [игнор отключен] [закрыт для гостей] / Проблема с ConcurrentHashMap / 25 сообщений из 99, страница 1 из 4
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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