`
DavyJones2010
  • 浏览: 151802 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Guava: Cache

阅读更多

1> MapMaker for creating ConcurrentMap instances.

2> CacheBuilder for creating LoadingCache and Cache instances.

3> CacheBuilderSpec for creating CacheBuilder instance from a formatted string

4> CacheLoader that is used by a LoadingCache instance to retrieve a single value for a given key

5> CacheStats that provides statistics of the performance of the cache

6> RemovalListener that receives notifications when an entry has been removed from the cache

 

1> MapMaker

    @Test
    public void makeMapTest() {
	Map<Object, Object> map = new MapMaker().concurrencyLevel(2)
		.weakValues().weakKeys().makeMap();
	map.put(new Object(), new Object());
    }

   Q: What's the meaning of "concurrencyLevel"?

   Q: What's the benefit of using "weakValues" and "weakKeys"?

 

2> Cache & LoadingCache

    1. Cache

public interface Cache<K, V> {
  void put(K key, V value);
  @Nullable
  V getIfPresent(Object key);
  V get(K key, Callable<? extends V> valueLoader) throws ExecutionException;
  /**
   * Returns a map of the values associated with {@code keys} in this cache. The returned map will
   * only contain entries which are already present in the cache.
   */
  ImmutableMap<K, V> getAllPresent(Iterable<?> keys);
  void invalidate(Object key);
  void invalidateAll(Iterable<?> keys);
  void invalidateAll();
  ConcurrentMap<K, V> asMap();
}

       1) get & getIfPresent

    @Test(expected = InvalidCacheLoadException.class)
    public void getTest() throws ExecutionException {
	Cache<String, String> cache = CacheBuilder.newBuilder().build();
	cache.put("KEY_1", "VALUE_1");
	String value = cache.getIfPresent("KEY_2");
	assertNull(value);

	value = cache.get("KEY_2", new Callable<String>() {
	    public String call() throws Exception {
		return "VALUE_2";
	    }
	});
	assertEquals("VALUE_2", value);

	value = cache.getIfPresent("KEY_2");
	assertEquals("VALUE_2", value);

	value = cache.get("KEY_2", new Callable<String>() {
	    public String call() throws Exception {
		return null;
	    }
	});
	assertEquals("VALUE_2", value);

	cache.invalidate("KEY_2");
	value = cache.get("KEY_2", new Callable<String>() {
	    public String call() throws Exception {
		return null; // InvalidCacheLoadException would be thrown
	    }
	});
    }

        The logic of cache.get(key, valueLoader) is:

            1> Find corresoponding value in cache with provided key

            2> If we can find its value, then the value is returned, valueLoader will NEVER be invoked.

            3> If we cannot find its value, then the valueLoader will be invoked to get the value.

                1> If valueLoader returns null, then CacheLoader$InvalidCacheLoadException will be thrown.

                2> If valueLoader returns not null value, then the value would be returned and then key/value pair would be stored in cache at the same time.

        Thus the thumbnail principle is that DO NOT RETURN NULL IN VALUELOADER.

        If we want return null if not cannot find its corresponding value, then use getIfPresent(key) instead.

        But the Callable implies that valueLoader is executed asynchronously, but what do we do if we don't need/want to execute an asynchronous task?

@Test
public void getTest() throws ExecutionException, InterruptedException {
	Cache<String, String> cache = CacheBuilder.newBuilder().build();
	Callable<String> callable = new Callable<String>() {
		@Override
		public String call() throws Exception {
			System.out.println("Thread: " + Thread.currentThread());
			Thread.sleep(1000);
			return "VALUE_" + System.currentTimeMillis();
		}
	};
	System.out.println(System.currentTimeMillis());
	String value = cache.get("KEY_1", callable);
	System.out.println(System.currentTimeMillis());
	System.out.println(value);
	value = cache.getIfPresent("KEY_1");
	System.out.println(System.currentTimeMillis());
	System.out.println(value);
}
// output:
// 1409031531671
// Thread: Thread[main,5,main]
// 1409031532699
// VALUE_1409031532684
// 1409031532699
// VALUE_1409031532684
    Q: It seems the callable is still executed in main thread, how can we start valueLoader asynchronously??
@Test
public void syncGetTest() throws ExecutionException {
	Cache<String, String> cache = CacheBuilder.newBuilder().build();
	System.out.println(System.currentTimeMillis());
	String value = cache.get("KEY_1",
	Callables.returning("VALUE_" + System.currentTimeMillis()));
	// What if the Callables.returning(timeConsumingService.get("KEY_1")) ?
	// Main thread still have to wait for the returning of this service.
	System.out.println(System.currentTimeMillis());
	System.out.println(value);
}
// output:
// 1409031825841
// 1409031825842
// 1409031825869
// VALUE_1409031825842

       2) invalidate & invalidateAll

@Test
public void invalidateTest() {
Cache<String, String> cache = CacheBuilder.newBuilder().build();
cache.put("KEY_1", "VALUE_1");
cache.put("KEY_2", "VALUE_2");
cache.put("KEY_3", "VALUE_3");
cache.put("KEY_4", "VALUE_4");

String value = cache.getIfPresent("KEY_1");
assertEquals("VALUE_1", value);

cache.invalidate("KEY_1");
value = cache.getIfPresent("KEY_1");
assertNull(value);

cache.invalidateAll(Lists.newArrayList("KEY_2", "KEY_3"));
value = cache.getIfPresent("KEY_2");
assertNull(value);
value = cache.getIfPresent("KEY_3");
assertNull(value);
value = cache.getIfPresent("KEY_4");
assertEquals("VALUE_4", value);
	
cache.invalidateAll();
value = cache.getIfPresent("KEY_4");
assertNull(value);
	
cache.invalidate("KEY_N");
}

    2. LoadingCache

public interface LoadingCache<K, V> extends Cache<K, V>, Function<K, V> {
  V get(K key) throws ExecutionException;
  V getUnchecked(K key);
  ImmutableMap<K, V> getAll(Iterable<? extends K> keys) throws ExecutionException;
  void refresh(K key);
  ConcurrentMap<K, V> asMap();
}

       The LoadingCache interface extends the Cache interface with the self-loading functionality.

       Consider the following code:

Book book = loadingCache.get(id);

        If the book object was not available when the get call was executed, LoadingCache will know how to retrieve the object, store it in the cache, and return the value.

        As implementations of LoadingCache are expected to be thread safe, a call made to get(), with the same key, while the cache is loading would block. Once the value was loaded, the call would return the value that was loaded by the orginal call to the get() method.

        However, multiple calls to get with distinct keys would load concurrently.

static LoadingCache<String, String> cache = CacheBuilder.newBuilder()
		.build(new CacheLoader<String, String>() {
			private int i = 1;
			@Override
			public String load(String key) throws Exception {
				Thread.sleep(1000);
				return "DUMMY_VALUE" + (++i);
			}
		});
@Test
public void syncLoadingTest() throws ExecutionException {
	System.out.println(System.currentTimeMillis());
	String value = cache.get("DUMMY_KEY"); // Blocking 1000ms for loading
	System.out.println(System.currentTimeMillis());
	System.out.println("Finished syncLoadingTest, value: " + value);
}
// output: We can see, the loading process cost 1000ms.
// 1409046809839
// 1409046810850
// Finished syncLoadingTest, value: DUMMY_VALUE2

@SuppressWarnings("unchecked")
@Test
public void asyncReadingTest() throws ExecutionException,
			InterruptedException {

	Callable<String> readThread1 = new Callable<String>() {
		@Override
		public String call() throws Exception {
			return cache.get("DUMMY_KEY_1");
		}
	};
	Callable<String> readThread2 = new Callable<String>() {
		@Override
		public String call() throws Exception {
			return cache.get("DUMMY_KEY_2");
		}
	};
	Callable<String> readThread3 = new Callable<String>() {
		@Override
		public String call() throws Exception {
			return cache.get("DUMMY_KEY_3");
		}
	};
	System.out.println("Before invokeAll: " + System.currentTimeMillis());
	Executors.newFixedThreadPool(3).invokeAll(
			Lists.newArrayList(readThread1, readThread2, readThread3));
	System.out.println("After invokeAll: " + System.currentTimeMillis());

	System.out.println("Before get: " + System.currentTimeMillis());
	String value1 = cache.get("DUMMY_KEY_1");
	String value2 = cache.get("DUMMY_KEY_2");
	String value3 = cache.get("DUMMY_KEY_3");
	System.out.println("After get: " + System.currentTimeMillis()
		+ ".\nvalue1: " + value1 + ", value2: " + value2 + ", value3:"
				+ value3);
}

// output: We can see, for all 3 values, the loading process only cost 1000ms.
// Before invokeAll: 1409046901047
// After invokeAll: 1409046902116
// Before get: 1409046902116
// After get: 1409046902116.
// value1: DUMMY_VALUE2, value2: DUMMY_VALUE2, value3:DUMMY_VALUE3

    If we have a collection of keys and would like to retrieve the values for each key, we will make the following call:

ImmutableMap<K, V> map = cache.getAll(Iterable<? extends K> keys);

    The map returned from getAll could either be all cached values, all newly retrieved values, or a mix of already cached and newly retrieved values.

    Q: The process of loading for uncached value is sync of async?

    A:  Sync:

static LoadingCache<String, String> cache = CacheBuilder.newBuilder()
		.build(new CacheLoader<String, String>() {
			private int i = 1;
			@Override
			public String load(String key) throws Exception {
				Thread.sleep(1000);
				return "DUMMY_VALUE" + (++i);
			}
		});

@Test
public void getAllTest() throws ExecutionException {
	System.out.println("Before getAllTest: " + System.currentTimeMillis());
	cache.getAll(Lists.newArrayList("KEY_1", "KEY_2", " KEY_3"));
	System.out.println("After getAllTest: " + System.currentTimeMillis());
}
// output: We can find the total time consumption is 3000ms
// Before getAllTest: 1409049717214
// After getAllTest: 1409049720343

    LoadingCache also provides a mechanism for refreshing values in the cache:

void refresh(K key);

    By making a call to refresh, LoadingCache will retrieve a new value for the key. The current value will not be discarded until the new value has been returned; this means that the calls to get during the loading process will return the current value in the cache. If an exception is thrown during the refresh call, the original value is kept in the cache. Kepp in mind that if the value is retrieved asynchronously, the method could return before the value is actually refreshed.

	static LoadingCache<String, String> cache = CacheBuilder.newBuilder()
			.build(new CacheLoader<String, String>() {
				private int i = 1;

				@Override
				public String load(String key) throws Exception {
					Thread.sleep(1000);
					return "DUMMY_VALUE" + (++i);
				}
			});

	/**
	 * Test for refresh() in loading cache <br/>
	 * The calls to get() during the loading process will return the current
	 * value in the cache <br/>
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		cache.put("DUMMY_KEY1", "DUMMY_VALUE1");

		Thread refreshThread = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					while (true) {
						Thread.sleep(1000);
						System.out.println("Start refresh KEY: DUMMY_KEY1");
						cache.refresh("DUMMY_KEY1");
						System.out.println("Finished refresh KEY: DUMMY_KEY1");
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});

		Thread getThread = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					while (true) {
						Thread.sleep(500);
						System.out.println("Start get KEY: DUMMY_KEY1");
						String value = cache.get("DUMMY_KEY1");
						System.out
								.println("Finished get KEY: DUMMY_KEY1, VALUE: "
										+ value);
					}
				} catch (ExecutionException e) {
					e.printStackTrace();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
		refreshThread.start();
		getThread.start();
	}

// output: We can find that during the course of refresh, we will still get the legacy value.
// Start get KEY: DUMMY_KEY1
// Finished get KEY: DUMMY_KEY1, VALUE: DUMMY_VALUE1
// Start get KEY: DUMMY_KEY1
// Start refresh KEY: DUMMY_KEY1
// Finished get KEY: DUMMY_KEY1, VALUE: DUMMY_VALUE1
// Start get KEY: DUMMY_KEY1
// Finished get KEY: DUMMY_KEY1, VALUE: DUMMY_VALUE1
// Start get KEY: DUMMY_KEY1
// Finished get KEY: DUMMY_KEY1, VALUE: DUMMY_VALUE1
// Finished refresh KEY: DUMMY_KEY1
// Start get KEY: DUMMY_KEY1
// Finished get KEY: DUMMY_KEY1, VALUE: DUMMY_VALUE2
// Start get KEY: DUMMY_KEY1
// Finished get KEY: DUMMY_KEY1, VALUE: DUMMY_VALUE2
// Start refresh KEY: DUMMY_KEY1
// Start get KEY: DUMMY_KEY1
// Finished get KEY: DUMMY_KEY1, VALUE: DUMMY_VALUE2

 

3> CacheBuilder

     The CacheBuilder class provides a way to obtain Cache and LoadingCache instances via the Builder pattern. There are many options we can specify on the Cache instance we are creating rather than listing all of them. 

     Eg1:

package edu.xmu.guava.cache;

import java.util.concurrent.TimeUnit;

import org.junit.Test;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;

public class CacheBuilderTest {
    @Test
    public void buildCacheTest() throws Exception {
	LoadingCache<String, String> cache = CacheBuilder.newBuilder()
		.expireAfterWrite(2, TimeUnit.SECONDS)
.ticker(Ticker.systemTicker())
		.removalListener(new RemovalListener<String, String>() {
		    @Override
		    public void onRemoval(
			    RemovalNotification<String, String> notification) {
			System.out.println(String.format(
				"[%s] is removed from cache", notification));
		    }
		}).build(new CacheLoader<String, String>() {
		    @Override
		    public String load(String key) throws Exception {
			return key + System.currentTimeMillis();
		    }
		});
	String value = cache.get("Hello");
	System.out.println(value);
	value = cache.get("Hello");
	System.out.println(value);
	Thread.sleep(2100);
	System.out.println(cache.size());
	Thread.sleep(1100);
	value = cache.get("Hello");
	System.out.println(value);
    }
}
// output: The new value is created after 3100ms instead of 2000ms, and when we get size at 2100ms, the size is 1 instead of 0.
// Hello1409057402516
// Hello1409057402516
// 1
// [Hello=Hello1409057402516] is removed from cache
// Hello1409057405725
    expireAfterWrite: When duration is zero, this method hands off to maximumSize(0), ignoring any otherwise-specificed maximum size or weight. This can be useful in testing, or to disable caching temporarily without a code change. Actually this expireAfterWrite will not remove this entry automatically when TimeUnit expires, it will remove entry when we visit it again and (CurrentTimestamp-LastAccessedTimestamp > TimeUnit).

    ticker: Specifies a nanosecond-precision time source for use in determining when entries should be expired. By default, System.nanoTime is used. The primary intent of this method is to facilitate testing of caches which have been configured with expireAfterWrite or expireAfterAccess. 

    Eg2:

@Test
public void maxSizeTest() throws ExecutionException {
  LoadingCache<String, String> cache = CacheBuilder.newBuilder()
	.maximumSize(3L)
	.removalListener(new RemovalListener<String, String>() {
	    @Override
	    public void onRemoval(
		    RemovalNotification<String, String> notification) {
		System.out.println(String.format(
			"[%s] is removed from cache", notification));
	    }
	}).build(new CacheLoader<String, String>() {
	    @Override
	    public String load(String key) throws Exception {
		return key + "_" + System.currentTimeMillis();
	    }
	});

  for (int i = 0; i < 12; i++) {
    System.out.println(cache.get(String.valueOf(i % 5)));
  }
}

// output:
0_1409058469045
1_1409058469046
2_1409058469046
[0=0_1409058469045] is removed from cache
3_1409058469046
[1=1_1409058469046] is removed from cache
4_1409058469055
[2=2_1409058469046] is removed from cache
0_1409058469055
[3=3_1409058469046] is removed from cache
1_1409058469055
[4=4_1409058469055] is removed from cache
2_1409058469055
[0=0_1409058469055] is removed from cache
3_1409058469055
[1=1_1409058469055] is removed from cache
4_1409058469055
[2=2_1409058469055] is removed from cache
0_1409058469056
[3=3_1409058469055] is removed from cache
1_1409058469056
    maximumSize: Less recently Used(LRU) entries are subject to be removed as the size of the cache approaches the maximum size number, not necessarily when the maxmium size is met or exceeded. That means if we set maximumSize = 100, there might be an occasion that some entries are removed when the size of the cache is 98 or even smaller. When size is zero, elements will be evicted immediately after being loaded into the cache. This can be useful in testing, or to disable caching temporarily without a code change. This feature cannot be used in conjunction with maxmiumWeight
public CacheBuilder<K, V> maximumSize(long size) {
  checkState(this.maximumSize == UNSET_INT, "maximum size was already set to %s",
  this.maximumSize);
  checkState(this.maximumWeight == UNSET_INT, "maximum weight was already set to %s",
  this.maximumWeight);
  checkState(this.weigher == null, "maximum size can not be combined with weigher");
  checkArgument(size >= 0, "maximum size must not be negative");
  this.maximumSize = size;
  return this;
}

    Eg3:

@Test
public void refreshTest() throws Exception {
  LoadingCache<String, String> cache = CacheBuilder.newBuilder()
	.refreshAfterWrite(1, TimeUnit.SECONDS)
	.build(new CacheLoader<String, String>() {
	    @Override
	    public String load(String key) throws Exception {
		return key + "_" + System.currentTimeMillis();
	    }
	});

  cache.put("DUMMY_KEY", "DUMMY_VALUE");
  System.out.println(cache.get("DUMMY_KEY"));
  Thread.sleep(1111);
  System.out.println(cache.get("DUMMY_KEY"));
  Thread.sleep(2111);
  System.out.println(cache.get("DUMMY_KEY"));
}
// output:
DUMMY_VALUE
DUMMY_KEY_1409060460794
DUMMY_KEY_1409060462915

    refreshAfterWrite: Instead of removing values explicitly, we are refreshing values after a given amount of thime has passed. Not that the trigger for the refreshing values is activated when the value is requested and the time limit has expired.

 

4> CacheBuilderSpec

    The CacheBuilderSpec class can be used to create a CacheBuilder instance by parsing a string that represents the settings for CacheBuilder, (with the caveat that we lose compile time checking a malformed string that in ture will lead to a runtime error). This is especially useful for command-line configuration of a CacheBuilder.

@Test
public void buildTest() throws ExecutionException {
  String spec = "refreshAfterWrite=5s,maximumSize=3";
  LoadingCache<String, String> cache = CacheBuilder.from(spec).build(
	new CacheLoader<String, String>() {
	    @Override
	    public String load(String key) throws Exception {
		return key + "_" + System.currentTimeMillis();
	    }
	});
  for (int i = 0; i < 10; i++) {
    System.out.println(cache.get(i % 6 + ""));
  }
}

    All configurable properties:

ImmutableMap.<String, ValueParser>builder()
          .put("initialCapacity", new InitialCapacityParser())
          .put("maximumSize", new MaximumSizeParser())
          .put("maximumWeight", new MaximumWeightParser())
          .put("concurrencyLevel", new ConcurrencyLevelParser())
          .put("weakKeys", new KeyStrengthParser(Strength.WEAK))
          .put("softValues", new ValueStrengthParser(Strength.SOFT))
          .put("weakValues", new ValueStrengthParser(Strength.WEAK))
          .put("expireAfterAccess", new AccessDurationParser())
          .put("expireAfterWrite", new WriteDurationParser())
          .put("refreshAfterWrite", new RefreshDurationParser())
          .put("refreshInterval", new RefreshDurationParser())
          .build();

    How did it realize this? Will dig into the source code in next chapter.

 

5> CacheStats

    How can we gather statistics on how our cache is performing and how it's being used? There is a very easy way to gather information on how our cache is performing. Keep in mind that tracking cache operations incurs a performance penalty.

@Test
public void recordStatsTest() throws Exception {
  LoadingCache<String, String> cache = CacheBuilder.newBuilder()
	.maximumSize(3L).expireAfterWrite(1L, TimeUnit.SECONDS)
	.recordStats().build(new CacheLoader<String, String>() {
	    @Override
	    public String load(String key) throws Exception {
		return key + "_" + System.currentTimeMillis();
	    }
	});
  System.out.println(cache.get("KEY_1"));
  System.out.println(cache.get("KEY_1"));
  Thread.sleep(2000);
  System.out.println(cache.get("KEY_1"));
  System.out.println(cache.stats());
}
// output: We can see the time consumption increased greatly if we trigger recordStats
KEY_1_1409062523824
KEY_1_1409062523824
KEY_1_1409062525827
CacheStats{hitCount=1, missCount=2, loadSuccessCount=2, loadExceptionCount=0, totalLoadTime=592797, evictionCount=1}

    The following list is an overview of the type of information that can be obtained from the cache:

    1> The average time spent loading new values

    2> The fraction of requests to the cache that were hits

    3> The fraction of requests to the cache that were misses

    4> The number of evictions made by the cache

 

6> RemovalNotification & RemovalListeners

    The RemovalNotification class implements Map.Entry interface, and as a result, we can access the actual key and value objects that compose then entry in the cache. We should note that these values could be null if then entry was removed due to GC. We can also determine the reason for the removal by calling the getCause() method on the RemovalNotification instance that returns a RemovalCause enum.

public enum RemovalCause {
EXPLICIT,
REPLACED,
COLLECTED,
EXPIRED,
SIZE;
}
@Test
public void removeTest() throws Exception {
  LoadingCache<String, String> cache = CacheBuilder.newBuilder()
	.maximumSize(3L).expireAfterWrite(1L, TimeUnit.SECONDS)
	.removalListener(new RemovalListener<String, String>() {
	    @Override
	    public void onRemoval(
		    RemovalNotification<String, String> notification) {
		System.out.println(String.format(
			"[%s] evicted from cache because of: [%s]",
			notification, notification.getCause()));
	    }
	}).build(new CacheLoader<String, String>() {
	    @Override
	    public String load(String key) throws Exception {
		return key + "_" + System.currentTimeMillis();
	    }
	});
  System.out.println(cache.get("KEY_1"));
  System.out.println(cache.get("KEY_1"));
  Thread.sleep(2000);
  System.out.println(cache.get("KEY_1"));
  cache.put("KEY_1", "DUMMY_VALUE");
  cache.invalidate("KEY_1");
  for (int i = 0; i < 5; i++) {
    cache.get("KEY_" + i);
  }
}
// output:
KEY_1_1409063533730
KEY_1_1409063533730
[KEY_1=KEY_1_1409063533730] evicted from cache because of: [EXPIRED]
KEY_1_1409063535733
[KEY_1=KEY_1_1409063535733] evicted from cache because of: [REPLACED]
[KEY_1=DUMMY_VALUE] evicted from cache because of: [EXPLICIT]
[KEY_0=KEY_0_1409063535733] evicted from cache because of: [SIZE]
[KEY_1=KEY_1_1409063535734] evicted from cache because of: [SIZE]

    The RemovalListeners class facilitates how we can asynchronously process the removal notifications. To enable our RemovalListener instance to process any work triggered by the removal of any entry, we simply use the RemovalListeners.asynchronous shown as follows:

@Test
public void asyncTest() throws Exception {
  RemovalListener<String, String> removalListener = RemovalListeners
	.asynchronous(new RemovalListener<String, String>() {
	    @Override
	    public void onRemoval(RemovalNotification<String, String> notification) {
		System.out.println(String.format(
			"[%s]: [%s] evicted from cache",
			Thread.currentThread(), notification));
		try {
		    Thread.sleep((long) (1000 * Math.random()));
		} catch (InterruptedException e) {
		    e.printStackTrace();
		}
	    }
	}, Executors.newFixedThreadPool(3));

  LoadingCache<String, String> cache = CacheBuilder.newBuilder()
	.maximumSize(3L).removalListener(removalListener)
	.build(new CacheLoader<String, String>() {
	    @Override
	    public String load(String key) throws Exception {
		return key + "_" + System.currentTimeMillis();
	    }
	});
  for (int i = 0; i < 6; i++) {
    System.out.println(cache.get(i + ""));
  }
}
// output:
0_1409064506708
1_1409064506709
2_1409064506709
3_1409064506709
4_1409064506719
[Thread[pool-1-thread-1,5,main]]: [0=0_1409064506708] evicted from cache
5_1409064506719
[Thread[pool-1-thread-2,5,main]]: [1=1_1409064506709] evicted from cache
[Thread[pool-1-thread-3,5,main]]: [2=2_1409064506709] evicted from cache

   Thus we have a thread pool which can handle the onRemoval event asynchronously.

 

 

Reference Links:

1> "Getting Started with Google Guava" - Bill Bejeck

分享到:
评论

相关推荐

    Guava-Cache本地缓存案例代码

    Guava Cache是Google Guava库中的一个强大特性,它提供了高效的本地缓存解决方案,用于存储经常访问的数据,以减少对远程服务或计算的调用,从而提高应用性能。本案例代码将详细介绍Guava Cache的使用,包括缓存的...

    guava-r09-jarjar.jar

    2. **缓存**:Guava的Cache模块允许开发者创建本地缓存,可以自动管理缓存项的过期和大小限制。 3. **函数式编程**:Guava提供了Function接口和其他相关类,支持函数式编程风格,可以方便地进行操作转换。 4. **...

    guava-cache.rar

    Guava Cache是Google Guava库中的一个强大特性,它提供了高效的本地缓存解决方案。在许多应用程序中,我们经常需要缓存数据以减少不必要的数据库查询或远程服务调用,提高系统性能。尽管分布式缓存如Redis在高并发和...

    Android代码-guava

    types, an in-memory cache, and APIs/utilities for concurrency, I/O, hashing, primitives, reflection, string processing, and much more! Guava comes in two flavors. The JRE flavor requires JDK 1.8 or ...

    springbt_guava_cache.7z

    2. Guava Cache:Google的Guava库中的Cache模块,是一个强大的本地缓存解决方案,支持线程安全、容量限制、自动过期等功能,适用于需要高性能缓存场景。 二、集成Guava Cache 在Spring Boot项目中,我们需要以下...

    Java内存缓存工具Guava LoadingCache使用解析

    Java内存缓存工具Guava LoadingCache使用解析 Java内存缓存工具Guava LoadingCache是一个非常强大的缓存工具,广泛应用于各种Java项目中。Guava Cache是单个应用运行时的本地缓存,用于将数据缓存到JVM内存中,提高...

    Go-Localcaching-GuavaCache在Go中的部分的实现

    Guava Cache是Java领域广泛使用的高效缓存解决方案,但Go语言本身并未直接提供与Guava Cache类似的功能。然而,开发者可以借鉴Guava Cache的设计理念,使用Go的标准库或者其他第三方库来实现类似的本地缓存机制。`...

    Springboot整合GuavaCache缓存过程解析

    SpringBoot整合GuavaCache缓存过程解析 SpringBoot是一款流行的Java框架,提供了许多便捷的功能来简化开发过程。其中,缓存机制是SpringBoot中的一个重要组件,可以帮助提高应用程序的性能和响应速度。GuavaCache是...

    详解Guava Cache本地缓存在Spring Boot应用中的实践

    详解Guava Cache本地缓存在Spring Boot应用中的实践 在高并发的互联网应用中,缓存的地位举足轻重,对提升程序性能帮助不小。Spring Boot默认使用的是SimpleCacheConfiguration,即使用ConcurrentMapCacheManager来...

    Guava-Cache-Demo:演示如何使用 Guava 缓存

    在这个名为 "Guava-Cache-Demo" 的项目中,我们将深入探讨如何利用 Guava Cache 来实现缓存机制,并通过一个实际示例——使用 Google Books API 获取 ISBN 对应图书详情——来展示其用法。 首先,我们需要理解 ...

    SpringBoot加入Guava Cache实现本地缓存代码实例

    SpringBoot 中 Guava Cache 的应用 在本文中,我们将介绍如何在 SpringBoot 项目中使用 Guava Cache 实现本地缓存。Guava Cache 是一个高性能的缓存框架,由 Google 开发维护。它提供了一个灵活的缓存机制,可以...

    Guava-CacheDemo.rar

    Guava Cache是Google Guava库中的一个功能强大的本地缓存实现,它为Java开发者提供了高效、易用的缓存解决方案。Guava Cache的设计目标是为了帮助应用程序在内存中存储经常访问的数据,以减少对远程服务或者数据库的...

    第七章 企业项目开发--本地缓存guava cache1

    【标题】:第七章 企业项目开发--本地缓存Guava Cache1 【描述】:在企业级项目开发中,缓存技术起着至关重要的作用,数据库设计往往也会考虑缓存策略。本地缓存和分布式缓存是常见的两种缓存方式,其中Guava Cache...

    Guava:Guava Google模块

    Guava还包含了一个强大的缓存模块,Cache,它支持基于时间和引用的自动过期、线程安全、异步加载等功能,可以方便地构建高性能的缓存系统。通过LoadingCache,你可以创建一个自动填充的缓存,当尝试获取一个不存在的...

    springboot使用GuavaCache做简单缓存处理的方法

    SpringBoot 使用 GuavaCache 实现简单缓存处理 在本篇文章中,我们将介绍如何使用 GuavaCache 在 SpringBoot 项目中实现简单的缓存处理。缓存机制可以减少对外部服务的查询请求,从而提高应用程序的性能。 问题...

    使用google guava 实现定时缓存功能

    创建一个Guava Cache对象,你可以通过`LoadingCache`接口,它在缓存项缺失时会自动加载。例如: ```java LoadingCache, Graph&gt; graphs = CacheBuilder.newBuilder() .maximumSize(1000) // 设置最大缓存容量 ....

    Getting Started with Google Guava code

    3. **并发工具**:Guava 提供了线程安全的数据结构,如 LoadingCache 和 Lists.newConcurrentList(),以及原子类和工作队列,帮助开发者编写高效且线程安全的代码。 4. **函数式编程**:Guava 支持函数式编程风格,...

    Collections源码java-lollipop_external_guava:Java平台的开放源代码库集合

    1. Cache:Guava的LoadingCache是缓存数据的工具,它可以自动加载缺失的值,支持异步更新,并且可以配置过期策略。 2. ListenableFuture:ListenableFuture扩展了Java的Future接口,允许添加监听器来处理完成、取消...

    guava(google的java集合包)

    2. **缓存机制**:Guava的Cache模块允许开发者创建本地缓存,可以自动管理内存并支持基于时间和引用的过期策略,有效提高了应用程序的性能。 3. **并发编程支持**:Guava提供了实用的并发工具类,如...

Global site tag (gtag.js) - Google Analytics