001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2011-2013 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.util; 011 012import mondrian.olap.Util; 013 014import java.util.concurrent.ConcurrentHashMap; 015 016/** 017 * A limited Map implementation which supports waiting for a value 018 * to be available when calling get(). Intended for use with 019 * producer/consumer queues, where a producer thread puts a value into 020 * the collection with a separate thread waiting to get that value. 021 * Currently used by the Actor implementations in 022 * <code>SegmentCacheManager</code> and <code>MonitorImpl</code>. 023 * 024 * <p><b>Thread safety</b>. BlockingHashMap is thread safe. The class 025 * delegates all get and put operations to a ConcurrentHashMap. </p> 026 * 027 * @param <K> request (key) type 028 * @param <V> response (value) type 029 */ 030public class BlockingHashMap<K, V> { 031 private final ConcurrentHashMap<K, SlotFuture<V>> map; 032 033 /** 034 * Creates a BlockingHashMap with given capacity. 035 * 036 * @param capacity Capacity 037 */ 038 public BlockingHashMap(int capacity) { 039 map = new ConcurrentHashMap<K, SlotFuture<V>>(capacity); 040 } 041 042 /** 043 * Places a (request, response) pair onto the map. 044 * 045 * @param k key 046 * @param v value 047 */ 048 public void put(K k, V v) { 049 map.putIfAbsent(k, new SlotFuture<V>()); 050 map.get(k).put(v); 051 } 052 053 /** 054 * Retrieves the response from the map matching the given key, 055 * blocking until it is received. 056 * 057 * @param k key 058 * @return value 059 * @throws InterruptedException if interrupted while waiting 060 */ 061 public V get(K k) throws InterruptedException { 062 map.putIfAbsent(k, new SlotFuture<V>()); 063 V v = Util.safeGet( 064 map.get(k), 065 "Waiting to retrieve a value from BlockingHashMap."); 066 map.remove(k); 067 return v; 068 } 069}