Я думаю, что вы ищете SUMIF
и SUMIFS
.
Если исходные данные указаны в Sheet1
, попробуйте:
=SUMIF(Sheet1!N:N,A2,Sheet1!K:K)
. =SUMIFS(Sheet1!$A:$A,Sheet1!$N:$N,$A2,Sheet1!O:O,"X")
. =SUMIFS(Sheet1!$A:$A,Sheet1!$N:$N,$A2,Sheet1!P:P,"X")
. Вы действительно не хотите синхронизироваться на Integer
, так как Вы не управляете тем, какие экземпляры являются тем же и какие экземпляры отличаются. Java просто не предоставляет такую услугу (если Вы не используете Целые числа в маленьком диапазоне), который надежен через другой JVMs. Если действительно необходимо синхронизироваться на Целом числе, то необходимо сохранить Карту или Набор Целого числа, таким образом, можно гарантировать, что Вы получаете точный экземпляр, который Вы хотите.
Лучше должен был бы создать новый объект, возможно, хранивший в HashMap
, который включается эти Integer
, для синхронизации на. Что-то вроде этого:
public Page getPage(Integer id) {
Page p = cache.get(id);
if (p == null) {
synchronized (getCacheSyncObject(id)) {
p = getFromDataBase(id);
cache.store(p);
}
}
}
private ConcurrentMap<Integer, Integer> locks = new ConcurrentHashMap<Integer, Integer>();
private Object getCacheSyncObject(final Integer id) {
locks.putIfAbsent(id, id);
return locks.get(id);
}
Для объяснения этого кода это использует ConcurrentMap
, который позволяет использование putIfAbsent
. Вы могли сделать это:
locks.putIfAbsent(id, new Object());
, но тогда Вы несете (маленькие) расходы создания Объекта для каждого доступа. Избегать, чтобы, я просто сохранил само Целое число в Map
. Чего это достигает? Почему это несколько отличается от просто использования самого Целого числа?
, Когда Вы делаете get()
от Map
, ключи по сравнению с [1 111] (или по крайней мере используемый метод является эквивалентом использования equals()
). Два различных Целочисленных экземпляра того же значения будут равны друг другу. Таким образом можно передать любое количество различных Целочисленных экземпляров" new Integer(5)
" как параметр к [1 114], и Вы будете всегда возвращать только самый первый экземпляр, который был передан в этом, содержал то значение.
существуют причины, почему Вы не можете хотеть синхронизироваться на [1 115]... можно войти в мертвые блокировки, если несколько потоков синхронизируются на [1 116] объекты и таким образом невольно используют те же блокировки, когда они хотят использовать различные блокировки. Можно зафиксировать этот риск при помощи
locks.putIfAbsent(id, new Object());
версия и таким образом несение (очень) маленькой стоимости для каждого доступа к кэшу. Делая это, Вы гарантируете, что этот класс будет делать свою синхронизацию на объекте, на котором не будет синхронизироваться никакой другой класс. Всегда Хорошая Вещь.
Integer.valueOf()
только возвраты кэшировали экземпляры для ограниченного диапазона. Вы не определили свой диапазон, но в целом, это не будет работать.
Однако я настоятельно рекомендовал бы не проявить этот подход, даже если значения находятся в корректном диапазоне. Начиная с этих кэшируемых Integer
экземпляры доступны любому коду, Вы не можете полностью управлять синхронизацией, которая могла привести к мертвой блокировке. Это - те же трудные люди, имеют попытку соединить результат String.intern()
.
лучшая блокировка является частной переменной. Так как только Ваш код может сослаться на него, можно гарантировать, что никакие мертвые блокировки не произойдут.
Между прочим, с помощью WeakHashMap
не будет работать также. Если экземпляр, служащий ключом, будет не имеющим ссылки, то он будет собран "мусор". И если на это сильно ссылаются, Вы могли бы использовать его непосредственно.
Используйте ориентированную на многопотоковое исполнение карту, такой как ConcurrentHashMap
. Это позволит Вам управлять картой безопасно, но использовать другую блокировку, чтобы сделать реальное вычисление. Таким образом у Вас могут быть множественные вычисления, работающие одновременный с единственной картой.
Использование ConcurrentMap.putIfAbsent
, но вместо того, чтобы поместить фактическое значение, использование Future
с в вычислительном отношении легкой конструкцией вместо этого. Возможно FutureTask
реализация. Выполните вычисление и затем get
результат, который ориентировано на многопотоковое исполнение заблокируется, пока не сделано.
Используя синхронизируемый на Целом числе звучит действительно неправильным дизайном.
, Если необходимо синхронизировать каждый объект индивидуально только во время, получают/хранят Вас, может создать Набор и сохранить там в настоящее время блокируемые объекты. В другом слова
// this contains only those IDs that are currently locked, that is, this
// will contain only very few IDs most of the time
Set<Integer> activeIds = ...
Object retrieve(Integer id) {
// acquire "lock" on item #id
synchronized(activeIds) {
while(activeIds.contains(id)) {
try {
activeIds.wait();
} catch(InterruptedExcption e){...}
}
activeIds.add(id);
}
try {
// do the retrieve here...
return value;
} finally {
// release lock on item #id
synchronized(activeIds) {
activeIds.remove(id);
activeIds.notifyAll();
}
}
}
то же переходит к хранилищу.
нижняя строка: нет никакой одной строки кода, который решает эту проблему точно способ, которым Вам нужно.
Как насчет ConcurrentHashMap с Целым числом возражает как ключи?
Вы могли взглянуть на этот код для создания взаимного исключения из идентификатора. Код был написан для Идентификаторов строки, но мог легко быть отредактирован для Целочисленных объектов.
Как Вы видите от множества ответов, существуют различные способы освежевать эту кошку:
Вы, возможно, должны не упустить потенциальную проблему с Antonio реализация , а именно, что notifyAll () разбудит потоки, ожидающие на весь идентификаторы, когда один из них станет доступным, который не может масштабироваться очень хорошо в соответствии с высокой конкуренцией. В принципе я думаю, что можно зафиксировать это при наличии объекта Условия для каждого в настоящее время блокируемого идентификатора, который является тогда вещью, которой Вы ждете/сигнализируете. Конечно, если на практике редко существует больше чем один идентификатор, ожидающий на в любой момент времени, то это не проблема.
Steve,
Ваш предложенный код имеет набор проблем с синхронизацией. (Antonio делает также).
Для суммирования:
псевдо код, чтобы заставить это произойти (использование ConcurrentHashMap как кэш):
ConcurrentMap<Integer, java.util.concurrent.Future<Page>> cache = new ConcurrentHashMap<Integer, java.util.concurrent.Future<Page>>;
public Page getPage(Integer id) {
Future<Page> myFuture = new Future<Page>();
cache.putIfAbsent(id, myFuture);
Future<Page> actualFuture = cache.get(id);
if ( actualFuture == myFuture ) {
// I am the first w00t!
Page page = getFromDataBase(id);
myFuture.set(page);
}
return actualFuture.get();
}
Примечание:
Посмотрите раздел 5.6 в Параллелизм Java на практике : "Создавая эффективный, масштабируемый, кэш результата". Это занимается точной проблемой, которую Вы пытаетесь решить. В частности, проверьте memoizer шаблон.
(источник: umd.edu )