A simple, asynchronous, single-threaded memcached client written in java.
Java Other
#33 Compare This branch is 1 commit ahead of dustin:master.
amcrn and Matt Ingenthron Fix ConcurrentModificationException for getStats Op
If the result of MemcachedClient.getStats() is immediately iterated
over, a ConcurrentModificationException can be thrown if the
operationTimeout value has been exceeded before mutations to the
Map have completed.


* blatch.await(operationTimeout, TimeUnit.MILLISECONDS); returns
  false after waiting `operationTimeout`, resulting in
  MemcachedClient.getStats() returning the `rv` Map.
* While the caller starts to iterate over the Map, the
  StatsOperation.Callback's gotStat mutates the Map, resulting in
  a ConcurrentModificationException.

How to Reproduce:

public static void main(String[] args) throws Exception {
  ConnectionFactory connectionFactory = new ConnectionFactoryBuilder()
  MemcachedClient client = new MemcachedClient(
    connectionFactory, AddrUtil.getAddresses("localhost:11211"));
  while(true) {
    Map<SocketAddress, Map<String, String>> allStats = client.getStats();
    if (allStats.isEmpty()) continue;
    Map<String, String> stats = allStats.entrySet().iterator().next().getValue();
    for(Entry<String,String> stat : stats.entrySet()) {
      System.out.println(stat.getKey() + " => " + stat.getValue());


2017-11-02 14:37:52.269 WARN net.spy.memcached.MemcachedClient:  Unsuccessful stat fetch: {OperationStatus success=false:  timed out}
Exception in thread "main" java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextEntry(HashMap.java:922)
	at java.util.HashMap$EntryIterator.next(HashMap.java:962)
	at java.util.HashMap$EntryIterator.next(HashMap.java:960)
	at com.xxx.xxx.xxx.xxx.xxx.StatsBug.main(StatsBug.java:31)


* Written in a way to be completely backwards compatible.
* Guarantees that the caller only sees the entire stats result for a
  SocketAddress, or no result at all. Converting the Maps to
  ConcurrentHashMaps alone would result in partially complete

Change-Id: If51e074a13f809581c8bad119b393edb2c4d4788
Reviewed-on: http://review.couchbase.org/91953
Reviewed-by: Matt Ingenthron <ingenthr@gmail.com>
Tested-by: Matt Ingenthron <ingenthr@gmail.com>
Latest commit eb5d6ee Nov 2, 2017



Spymemcached can be compiled using Apache Ant by running the following command:


This will generate binary, source, and javadoc jars in the build directory of the project.

To run the Spymemcached tests against Membase Server run the following command:

ant test -Dserver.type=membase

To test Spymemcached against Membase running on a different host use the following command:

ant test -Dserver.type=membase \


The latest version of spymemcached has a set of command line arguments that can be used to configure the location of your testing server. The arguments are listed below.


This argument is used to specify the ipv4 address of your testing server. By default it is set to localhost.


This argument is used to set the ipv6 address of your testing server. By default it is set to ::1. If an ipv6 address is specified then an ipv4 address must be specified otherwise there may be test failures.


This argument is used when memcahched is started on a port other than 11211


This argument is used for CI testing where certain unit tests might be temporarily failing.

More Information

For more information about Spymemcached see the links below:

Project Page The

Spymemcached Project Home contains a wiki, issue tracker, and downloads section.


The gitub page contains the latest Spymemcached source.


At couchbase.org you can find a download's section for the latest release as well as an extensive tutorial to help new users learn how to use Spymemcached.