Of course! Here is a comprehensive guide to using a Java Memcache client, focusing on the most popular and feature-rich option, Xmemcached.

Overview: Java Memcache Clients
Memcached is a high-performance, distributed memory caching system. To interact with it from a Java application, you need a client library. The most commonly used and recommended Java clients are:
- Xmemcached: The modern, feature-rich, and actively maintained choice. It's highly recommended for new projects.
- SpyMemcached: An older, very stable client. It's still used but has seen less development recently.
- Whalin (Java Memcached Client): Another older client, largely superseded by the other two.
For this guide, we will focus on Xmemcached due to its superior performance, features like support for the binary protocol and SASL authentication, and active community.
Step-by-Step Guide with Xmemcached
Step 1: Add the Dependency
First, you need to add the Xmemcached library to your project. If you're using Maven, add this to your pom.xml:
<dependency>
<groupId>com.googlecode.xmemcached</groupId>
<artifactId>xmemcached</artifactId>
<version>2.4.7</version> <!-- Check for the latest version on Maven Central -->
</dependency>
If you're using Gradle, add this to your build.gradle:

implementation 'com.googlecode.xmemcached:xmemcached:2.4.7' // Check for the latest version
Step 2: Basic Setup and Connection
The core of Xmemcached is the MemcachedClient class. You need to create an instance and connect it to your Memcached server(s).
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.XMemcachedClient;
import net.rubyeye.xmemcached.utils.AddrUtil;
public class MemcachedExample {
public static void main(String[] args) {
// The Memcached server address. For multiple servers, separate with spaces.
// e.g., "localhost:11211 localhost:11212"
String serverAddress = "localhost:11211";
try {
// 1. Create a MemcachedClient instance
// AddrUtil.getAddresses() parses the address string into a list of InetSocketAddress
MemcachedClient memcachedClient = new XMemcachedClient(AddrUtil.getAddresses(serverAddress));
System.out.println("Successfully connected to Memcached server.");
// ... perform operations ...
// 3. Shut down the client gracefully
memcachedClient.shutdown();
} catch (Exception e) {
System.err.println("Error connecting to Memcached: " + e.getMessage());
e.printStackTrace();
}
}
}
Step 3: Performing Basic Operations
Xmemcached provides a simple set, get, delete API. The key methods are generic, allowing you to store any Serializable object.
Storing Data (set)
The set method stores a key-value pair with an optional expiration time (in seconds).
// Set a string value with an expiration of 3600 seconds (1 hour)
memcachedClient.set("user:1001:username", 3600, "john_doe");
// Set an integer value
memcachedClient.set("session:abc123:counter", 0, 10);
// Set a custom Java object (it must implement Serializable)
User user = new User("jane_doe", "jane@example.com");
memcachedClient.set("user:1002", 3600, user);
Retrieving Data (get)
The get method retrieves a value by its key.

// Get a string value
String username = memcachedClient.get("user:1001:username");
System.out.println("Username: " + username);
// Get an integer value
Integer counter = memcachedClient.get("session:abc123:counter");
System.out.println("Counter: " + counter);
// Get a custom Java object
User retrievedUser = memcachedClient.get("user:1002");
System.out.println("Retrieved User: " + retrievedUser.getName());
Deleting Data (delete)
The delete method removes a key-value pair from the cache.
// Delete the key
boolean deleted = memcachedClient.delete("user:1001:username");
System.out.println("Key deleted: " + deleted);
Step 4: Advanced Operations
cas (Check-And-Set) for Atomic Operations
cas is a powerful atomic operation that allows you to update a value only if it hasn't been changed by another client since you last fetched it. This is perfect for implementing locks or counters.
The gets method returns both the value and a unique cas ID.
// 1. Get the value and its CAS ID
CASValue<Integer> casValue = memcachedClient.gets("session:abc123:counter");
Integer currentCounter = casValue.getValue();
long casId = casValue.getCas();
System.out.println("Current counter: " + currentCounter + " with CAS ID: " + casId);
// 2. Increment the counter
int newCounter = currentCounter + 1;
// 3. Try to set the new value using the CAS ID
// This will only succeed if the value hasn't been modified.
boolean casResult = memcachedClient.cas("session:abc123:counter", casId, newCounter, 0);
System.out.println("CAS operation successful: " + casResult);
// If another client had updated the counter, the casResult would be false.
append and prepend
These operations add data to the beginning or end of an existing value.
// First, set a base value
memcachedClient.set("message:1", 0, "Hello ");
// Append to the existing value
memcachedClient.append("message:1", "World!");
// Prepend to the existing value
memcachedClient.prepend("message:1", "Say: ");
// Get the final result
String finalMessage = memcachedClient.get("message:1");
System.out.println("Final message: " + finalMessage); // Output: Say: Hello World!
Incr and Decr (Atomic Increment/Decrement)
For counters, it's much more efficient to use the built-in atomic increment and decrement operations.
// Set an initial value for the counter
memcachedClient.set("global:hit_count", 0, 100);
// Increment by 5
long newCount = memcachedClient.incr("global:hit_count", 5);
System.out.println("Counter after increment: " + newCount); // 105
// Decrement by 2
long afterDecr = memcachedClient.decr("global:hit_count", 2);
System.out.println("Counter after decrement: " + afterDecr); // 103
Step 5: Error Handling and Best Practices
- Connection Management: Always shut down the
MemcachedClientwhen your application shuts down to release resources. - Timeouts: Configure connection, operation, and read timeouts to prevent your application from blocking indefinitely if the Memcached server is slow or unresponsive.
MemcachedClientBuilder: For production, useMemcachedClientBuilderfor more advanced configuration, including connection pools and timeouts.
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.auth.AuthInfo;
import net.rubyeye.xmemcached.utils.AddrUtil;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.List;
public class AdvancedMemcachedSetup {
public static void main(String[] args) throws IOException {
String serverAddress = "localhost:11211";
MemcachedClientBuilder builder = new XMemcachedClientBuilder(
AddrUtil.getAddresses(serverAddress)
);
// Configure connection pool and timeouts
builder.setConnectionPoolSize(10); // Number of connections to keep open
builder.setOpTimeout(1000); // Operation timeout in milliseconds
builder.setConnectTimeout(2000); // Connection timeout in milliseconds
// If your Memcached server requires authentication
builder.addAuthInfo(AddrUtil.getOneAddress(serverAddress),
AuthInfo.plain("username", "password"));
MemcachedClient memcachedClient = builder.build();
try {
// Use the client...
memcachedClient.set("test", 0, "Hello Advanced!");
String value = memcachedClient.get("test");
System.out.println("Value: " + value);
} finally {
// Ensure the client is shut down
memcachedClient.shutdown();
}
}
}
Comparison: Xmemcached vs. SpyMemcached
| Feature | Xmemcached | SpyMemcached |
|---|---|---|
| Protocol | Supports both Text and Binary protocols. Binary is faster. | Text protocol only. |
| SASL Auth |
