У меня есть программа, состоящая из нескольких классов. У меня проблема с взаимодействием двух классов - WebDataCache и Client. Классы проблем перечислены ниже.
WebData:
Это просто класс данных, представляющий некоторые данные, полученные из Интернета.
WebService:
Это просто класс-оболочка веб-службы, который подключается к определенной веб-службе, считывает некоторые данные и сохраняет их в объекте типа WebData.
WebDataCache:
Это класс, который использует класс WebService для извлечения данных, которые кэшируются на карте, на основе полей идентификаторов данных.
Клиент:
Это класс, который содержит ссылку на экземпляр класса WebDataCache и использует кэшированные данные.
Проблема заключается в том (как показано ниже), когда класс циклически перебирает кэшированные данные, возможно, WebDataCache обновляет базовую коллекцию.
У меня вопрос, как мне синхронизировать доступ к кешу?
Я не хочу синхронизировать весь кэш, поскольку существует несколько экземпляров класса Client, однако каждый экземпляр создается с уникальным идентификатором (т. Е. New Client (0, ...), new Client (1, ... ), новый клиент (2, ...) и т. д. каждый экземпляр заинтересован только в данных, идентифицированных идентификатором, с которым был создан клиент.
Есть ли подходящие шаблоны проектирования, которые я могу использовать?
class WebData {
private final int id;
private final long id2;
public WebData(int id, long id2) {
this.id = id;
this.id2 = id2;
}
public int getId() { return this.id; }
public long getId2() { return this.id2; }
}
class WebService {
Collection<WebData> getData(int id) {
Collection<WebData> a = new ArrayList<WebData>();
// populate A with data from a webservice
return a;
}
}
class WebDataCache implements Runnable {
private Map<Integer, Map<Long, WebData>> cache =
new HashMap<Integer, Map<Long, WebData>>();
private Collection<Integer> requests =
new ArrayList<Integer>();
@Override
public void run() {
WebService webSvc = new WebService();
// get data from some web service
while(true) {
for (int id : requests) {
Collection<WebData> webData = webSvc.getData(id);
Map<Long, WebData> row = cache.get(id);
if (row == null)
row = cache.put(id, new HashMap<Long, WebData>());
else
row.clear();
for (WebData webDataItem : webData) {
row.put(webDataItem.getId2(), webDataItem);
}
}
Thread.sleep(2000);
}
}
public synchronized Collection<WebData> getData(int id){
return cache.get(id).values();
}
public synchronized void requestData(int id) {
requests.add(id);
}
}
-
class Client implements Runnable {
private final WebDataCache cache;
private final int id;
public Client(int id, WebDataCache cache){
this.id = id;
this.cache = cache;
}
@Override
public void run() {
cache.requestData(id);
while (true) {
for (WebData item : cache.getData(id)) {
// java.util.ConcurrentModificationException is thrown here...
// I understand that the collection is probably being modified in WebDataCache::run()
// my question what's the best way to sychronize this code snippet?
}
}
}
}
Спасибо!