8

я использовал HashMap перед тем, какJava ConcurrentHashMap не потокобезопасен .. wth?

public Map<SocketChannel, UserProfile> clients = new HashMap<SocketChannel, UserProfile>(); 

теперь я переключился на ConcurrentHashMap, чтобы избежать синхронизированных блоков и теперь я испытывающие проблемы мой сервер сильно загружен 200-400 одновременных клиентов каждый второй, который, как ожидается, со временем.

, который теперь выглядит как этот

public ConcurrentHashMap<SocketChannel, UserProfile> clients = new ConcurrentHashMap<SocketChannel, UserProfile>(); 

дизайн Мой сервер работает следующим образом. У меня есть рабочий поток (ы) для обработки огромного количества пакетов. Каждый пакет проверяется с помощью подпрограммы packageHandler (а не части потока), практически любой клиент может вызвать его в любое время, когда он почти как статический, но это не так.

Весь мой сервер в основном однопоточный, за исключением части обработки пакета.

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

Возможно также, что клиенты могут быть отсоединены и удалены с ConcurrentHashMap, пока выполняется подсчет (что вызывает мои проблемы).

Также я хотел бы добавить здесь код.

   int txtGirls=0; 
       int vidGirls=0; 
       int txtBoys=0; 
       int vidBoys=0; 
       Iterator i = clients.values().iterator(); 
       while (i.hasNext()) { 
        UserProfile person = (UserProfile)i.next(); 
        if(person != null) { 
         if(person.getChatType()) { 
          if(person.getGender().equals("m")) 
           vidBoys++; 
          else //<-- crash occurs here. 
           vidGirls++; 
         } else if(!person.getChatType()) { 
          if(person.getGender().equals("m")) 
           txtBoys++; 
          else 
           txtGirls++; 
         } 
        } 
       } 

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

Но то, что я не понимаю, если он проверяет выше, если (человек! = NULL) не должен код вложен автоматически работает ..

если это не означает, что он был удален в то время как он был итерации, который должно быть невозможно, так как это потокобезопасный wtf?

Что мне делать? или является попыткой исключить лучший способ?

Вот исключение

java.lang.NullPointerException 
    at Server.processPackets(Server.java:398) 
    at PacketWorker.run(PacketWorker.java:43) 
    at java.lang.Thread.run(Thread.java:636) 

В processPackets содержит код, указанный выше. и в комментарии указано количество строк #

Спасибо, что просветили меня.

+0

Вы пробовали Collections.synchronizedMap (Карта)? – zengr

+5

«TF» - это то, что ConcurrentHashMap ** является потокобезопасным, но вы ожидаете чего-то еще над безопасностью потоков. –

+1

это также поможет, если вы объясните, что означает «авария здесь». Какая «авария»? Какое исключение? –

ответ

16

Вы должны прочитать Javadocs для метода ConcurrentHashMap.values(), обращая особое внимание на это описание того, как итератор для values() коллекции работ:

«Итератор представления - это« слабо согласованный »итератор, который никогда не будет бросать ConcurrentModificationException и гарантирует пересечение элементов, как они существовали при построении итератора, и может (но не является гарантией d) отражают любые изменения после строительства ».

Итератор не дает последовательный снимок состояния коллекции значений, но это поточно-, а ожидаемый диапазон поведений четко указано.

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

+0

Спасибо, кто-то должен был опустить это для меня, поскольку я простой человек.Но я не понимаю, сохраняет ли коллекция значений во время итерации, и она не может содержать значение null, почему я получаю исключение nullpointer? это справочная проблема, тогда да ... поэтому эти ссылки связаны как адреса одного и того же класса. Другие, а затем расходуют на CocurrentHashMap, что? атомически вы имеете в виду как собственный метод копирования? nevermind я нашел его Пакет java.util.concurrent.atomic – SSpoke

+0

Под «атомарным» я имею в виду как одно непрерывное действие; см. http://en.wikipedia.org/wiki/Atomicity_%28programming%29. BTW, в Java нет такой вещи, как (атомный) собственный метод копирования. Единственные способы гарантировать атомарность в Java - это использовать примитивную или 'java.util.concurrent. *' Блокировку или использование 'volatile'. Оба подхода имеют оговорки. –

+3

@SSpoke - если NPE произошел именно в указанной вами точке, это, вероятно, не из-за «null», возвращаемого итератором. Скорее, 'person.getGender()' вернул 'null'. –

1

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

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

Вот несколько ссылок, которые могут быть полезны:

Это один говорит немного о том, что улучшение параллелизм из-за расслаблением некоторых обещаний. http://www.ibm.com/developerworks/java/library/j-jtp07233.html

свойства непротиворечивости памяти объяснил: http://download-llnw.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility

+0

true .. Я трачу много циклов процессора, но переопределение CocurrentHashMap кажется слишком сложным, потому что это всего лишь одна команда .. и еще много команд, которые следуют за аналогичными вещами. – SSpoke

+0

Эй, Джеймс, я могу быть уверен в том, что на 100%? если класс UserProfile, который назначается каждому клиенту, копируется в новую коллекцию, которую я буду повторять, если CocurrentHashMap удаляет этот UserProfile, а не ссылку (указатель?) то же самое? что означает, что оба будут удалены? можешь ли ты это понять для меня. – SSpoke

1

Я не вижу ничего плохого в вашем коде. Поскольку маловероятно, что авария на самом деле происходит на else, вполне вероятно, что метод getGender() возвращает null.

+0

Да, это так .. но это потому, что человек пуст. Кажется, я пойду с идеей копирования значений в коллекции? idk, если это решит его? – SSpoke

+2

@SSpoke в вашем коде нельзя использовать для 'person.getChatType()', чтобы не разыменовывать нуль, а затем 'person.getGender()' для разыменования null. Я думаю, вы неверно истолковываете свое исключение NullPointerException. –

+0

Вы правы Джейкоб и Стив – SSpoke

3

java.util.concurrent.ConcurrentHashMap делает не разрешить null значение. Таким образом, null check (person! = Null) в вашем коде не требуется.

Если вы хотите отказаться от модификации карты во время итерации, вы должны использовать блок синхронизации в приведенном выше коде и кодах операций модификации.

+0

Спасибо за то, что я его удалю (надеюсь, вы не говорите дезинформацию, извините за груб). Но благодаря вам, ребята, я каждый день узнаю новый трюк! – SSpoke

+2

@SSpoke JavaDoc дает понять, что @heekyu не говорит о дезинформации. http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentHashMap.html –