Хранение данных в DefaultListModel vs ConcurrentHashMap
Я пишу графический интерфейс в swing для отображения несогласованных запросов от клиентов. Сервер заполняет LinkedBlockingQueue
, в то время как другой поток берет из очереди, когда есть доступные данные. Запросы хранятся в виде Object
. Вот так:
while(should_take) {
//getRequest() is blocking
Object request = server.getRequest();
//Add request to user interface
GUI.addToList(request);
}
Теперь мой вопрос, не лучше ли было бы:
Решение 1:
Храните request
в ConcurrentHashMap<Integer, Object>
с ключом в качестве хэша запроса и значением в качестве объекта. Затем я буду использовать a DefaultListModel
для хранения идентификатор (напр. тип запроса) запроса и хэш-значения. DefaultListModel
будет использоваться для заполнения JList
, эффективно отображая запрос пользователю. Значение запросаselected (выбранного пользователем) затем может быть извлечено из ConcurrentHashMap с помощью хэша, сохраненного в DefaultListModel
.
Пример кода:
ConcurrentHashMap<Integer, Object> requests = new ConcurrentHashMap<>();
DefaultListModel listData = new DefaultListModel();
JList theList = new JList();
...
public void addToList(Object request) {
//Place in HashMap
requests.put(request.hashCode(), request);
//Create a DataHolder with the Hashvalue and identifier of the request
DataHolder holder = new DataHolder(request.getID(), request.hash);
//Add the element to the ListModel
listData.addElement(holder);
//Assign the list model to the JList
theList.setModel(listData);
}
Когда пользователь выбирает элемент в списке:
DataHolder holder = (DataHolder)theList.getSelectedValue();
//Get request from HashMap
Object request = requests.get(holder.getHash());
//Do something with request
Решение 2:
Я заполняю новый объект, назовите его DataHolder
, с идентификатором запроса и значением запроса. Теперь я могу заполнить JList
с DefaultListModel
, который содержит DataHolder
, и никакая ссылка не требуется на любую другую структуру данных, чтобы получить фактическое значение запроса. Поскольку DefaultListModel
используется для заполнения JList
, я чувствую, что это может повлиять на производительность и может привести к тому, что список будет заполняться/не заполняться медленнее.
Пример кода:
DefaultListModel listData = new DefaultListModel();
JList theList = new JList();
...
public void addToList(Object request) {
//Removed HashMap
//Create a DataHolder with the Hashvalue and *actual value* of the request
DataHolder holder = new DataHolder(request.getID(), request);
//Add the element to the ListModel
listData.addElement(holder);
//Assign the list model to the JList
theList.setModel(listData);
}
Когда пользователь выбирает элемент в списке:
//No more HashMap
DataHolder holder = (DataHolder)theList.getSelectedValue();
Object request = holder.getData();
//Do something with request
Какое решение будет дать более быстрые результаты? Есть ли более эффективный способ сделать это? Любая помощь в этом вопросе будет очень признательна.
Еще немного информации:
- Запрос может подаваться в виде пакетов. (50+ за серию)
- запросы будут состоять из 20-50 строк XML
- запросы будут удалены из структуры данных случайным образом
Правка:
Последовательность, добавляющая сообщения в список, теперь обернута вinvokeLater
. С моей реализацией, каждый раз, когда сообщение будет добавлено в список, будет создан новый поток, который выполнит всю работу и завершится, как только сообщение окажется в списке. Конечно, это влияет на ответ. Если 50 потоков создаются в плотной последовательности (с каждым вызовом addToList), какое решение будет выполняться быстрее?1 ответ:
Решение 3: Расширить
SwingWorker
,class MessageWorker extends SwingWorker<List<DataHolder>, DataHolder> {}
В вашей реализации
doInBackground()
,publish()
промежуточные результаты по мере их появления. При реализацииprocess()
, обновление модели представления компонента. Удобно, чтоSwingWorker
будет объединятьpublish()
вызовы в устойчивом темпе. профиль ваше приложение для проверки. Другие примеры можно найти здесь.