diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index 6f96e1e..3279845 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -1506,6 +1506,9 @@
   [#^clojure.lang.Ref ref val]
     (. ref (set val)))
 
+(defmacro invariant [& body]
+  `(clojure.lang.LockingTransaction/invariant (fn [] ~@body)))
+
 (defn ref-history-count
   "Returns the history count of a ref"
   [#^clojure.lang.Ref ref]
diff --git a/src/jvm/clojure/lang/LockingTransaction.java b/src/jvm/clojure/lang/LockingTransaction.java
index ab69e22..1619f50 100644
--- a/src/jvm/clojure/lang/LockingTransaction.java
+++ b/src/jvm/clojure/lang/LockingTransaction.java
@@ -93,6 +93,7 @@ void stop(int status){
 		vals.clear();
 		sets.clear();
 		commutes.clear();
+		invariants.clear();
 		//actions.clear();
 		}
 }
@@ -107,6 +108,7 @@ final ArrayList<Agent.Action> actions = new ArrayList<Agent.Action>();
 final HashMap<Ref, Object> vals = new HashMap<Ref, Object>();
 final HashSet<Ref> sets = new HashSet<Ref>();
 final TreeMap<Ref, ArrayList<CFn>> commutes = new TreeMap<Ref, ArrayList<CFn>>();
+final HashMap<IFn, Object> invariants = new HashMap<IFn, Object>();
 
 final HashSet<Ref> ensures = new HashSet<Ref>();   //all hold readLock
 
@@ -285,10 +287,6 @@ Object run(Callable fn) throws Exception{
 						}
 					Object val = ref.tvals == null ? null : ref.tvals.val;
 					vals.put(ref, val);
-					for(CFn f : e.getValue())
-						{
-						vals.put(ref, f.fn.applyTo(RT.cons(vals.get(ref), f.args)));
-						}
 					}
 				for(Ref ref : sets)
 					{
@@ -296,6 +294,19 @@ Object run(Callable fn) throws Exception{
 					locked.add(ref);
 					}
 
+				for (Map.Entry<IFn, Object> e : invariants.entrySet())
+					if (!Util.equiv(e.getValue(), e.getKey().invoke()))
+							throw retryex;
+
+				for(Map.Entry<Ref, ArrayList<CFn>> e : commutes.entrySet())
+					{
+					Ref ref = e.getKey();
+					for(CFn f : e.getValue())
+						{
+							vals.put(ref, f.fn.applyTo(RT.cons(vals.get(ref), f.args)));
+						}
+					}
+
 				//validate and enqueue notifications
 				for(Map.Entry<Ref, Object> e : vals.entrySet())
 					{
@@ -482,6 +493,16 @@ Object doCommute(Ref ref, IFn fn, ISeq args) throws Exception{
 	return ret;
 }
 
+Object doInvariant(IFn fn) throws Exception{
+	Object val = fn.invoke();
+	invariants.put(fn, val);
+	return val;
+}
+
+static public Object invariant(IFn fn) throws Exception{
+	return LockingTransaction.getRunning().doInvariant(fn);
+}
+
 /*
 //for test
 static CyclicBarrier barrier;
