diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisAtomicLong.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisAtomicLong.java
new file mode 100644
index 000000000..64775e673
--- /dev/null
+++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisAtomicLong.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2006-2009 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.datastore.redis.util;
+
+import java.io.Serializable;
+
+import org.springframework.datastore.redis.connection.RedisCommands;
+
+/**
+ * Atomic long backed by Redis.
+ * Uses Redis atomic increment/decrement and watch/multi/exec commands for CAS operations.
+ *
+ * @see java.util.concurrent.atomic.AtomicLong
+ * @author Costin Leau
+ */
+public class RedisAtomicLong extends Number implements Serializable {
+
+ private final String key;
+ private RedisCommands commands;
+
+ /**
+ * Constructs a new RedisAtomicLong instance with an initial value of zero.
+ *
+ * @param redisCounter
+ * @param commands
+ */
+ public RedisAtomicLong(String redisCounter, RedisCommands commands) {
+ this(redisCounter, commands, 0);
+ }
+
+ /**
+ * Constructs a new RedisAtomicLong instance with the given initial value.
+ *
+ * @param redisCounter
+ * @param commands
+ * @param initialValue
+ */
+ public RedisAtomicLong(String redisCounter, RedisCommands commands, long initialValue) {
+ this.key = redisCounter;
+ this.commands = commands;
+ commands.set(redisCounter, Long.toString(initialValue));
+ }
+
+ /**
+ * Gets the current value.
+ *
+ * @return the current value
+ */
+ public long get() {
+ return Long.valueOf(commands.get(key));
+ }
+
+ /**
+ * Sets to the given value.
+ *
+ * @param newValue the new value
+ */
+ public void set(long newValue) {
+ commands.set(key, Long.toString(newValue));
+ }
+
+ /**
+ * Atomically sets to the given value and returns the old value.
+ *
+ * @param newValue the new value
+ * @return the previous value
+ */
+ public long getAndSet(long newValue) {
+ return Long.valueOf(commands.getSet(key, Long.toString(newValue)));
+ }
+
+ /**
+ * Atomically sets the value to the given updated value
+ * if the current value {@code ==} the expected value.
+ *
+ * @param expect the expected value
+ * @param update the new value
+ * @return true if successful. False return indicates that
+ * the actual value was not equal to the expected value.
+ */
+ public boolean compareAndSet(long expect, long update) {
+ for (;;) {
+ commands.watch(key);
+ if (expect == get()) {
+ commands.multi();
+ set(update);
+ if (commands.exec() != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Atomically increments by one the current value.
+ *
+ * @return the previous value
+ */
+ public long getAndIncrement() {
+ for (;;) {
+ commands.watch(key);
+ long value = get();
+ commands.multi();
+ commands.incr(key);
+ if (commands.exec() != null) {
+ return value;
+ }
+ }
+ }
+
+ /**
+ * Atomically decrements by one the current value.
+ *
+ * @return the previous value
+ */
+ public long getAndDecrement() {
+ for (;;) {
+ commands.watch(key);
+ long value = get();
+ commands.multi();
+ commands.decr(key);
+ if (commands.exec() != null) {
+ return value;
+ }
+ }
+ }
+
+ /**
+ * Atomically adds the given value to the current value.
+ *
+ * @param delta the value to add
+ * @return the previous value
+ */
+ public long getAndAdd(long delta) {
+ for (;;) {
+ commands.watch(key);
+ long value = get();
+ commands.multi();
+ set(value + delta);
+ if (commands.exec() != null) {
+ return value;
+ }
+ }
+ }
+
+ /**
+ * Atomically increments by one the current value.
+ *
+ * @return the updated value
+ */
+ public long incrementAndGet() {
+ return commands.incr(key);
+ }
+
+ /**
+ * Atomically decrements by one the current value.
+ *
+ * @return the updated value
+ */
+ public long decrementAndGet() {
+ return commands.decr(key);
+ }
+
+ /**
+ * Atomically adds the given value to the current value.
+ *
+ * @param delta the value to add
+ * @return the updated value
+ */
+ public long addAndGet(long delta) {
+ // TODO: is this really safe
+ return commands.incrBy(key, (int) delta);
+ }
+
+ /**
+ * Returns the String representation of the current value.
+ * @return the String representation of the current value.
+ */
+ public String toString() {
+ return Long.toString(get());
+ }
+
+
+ public int intValue() {
+ return (int) get();
+ }
+
+ public long longValue() {
+ return (long) get();
+ }
+
+ public float floatValue() {
+ return (float) get();
+ }
+
+ public double doubleValue() {
+ return (double) get();
+ }
+}
\ No newline at end of file