diff --git a/test/build.xml b/test/build.xml
index 1036f8f05f5de6be99ef9455073b9480bea1fc80..67ff69ddcb8dce1966dab6b7955cb2ce1ed7e79e 100644
--- a/test/build.xml
+++ b/test/build.xml
@@ -14,6 +14,7 @@
 				<path refid='util-classes'/>
 			</classpath>
 			<test name='net.sf.briar.FileReadWriteTest'/>
+			<test name='net.sf.briar.LockFairnessTest'/>
 			<test name='net.sf.briar.crypto.CounterModeTest'/>
 			<test name='net.sf.briar.db.BasicH2Test'/>
 			<test name='net.sf.briar.db.DatabaseCleanerImplTest'/>
diff --git a/test/net/sf/briar/LockFairnessTest.java b/test/net/sf/briar/LockFairnessTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..57a6daed16f93ab107cbd9df41379298a25ac4f2
--- /dev/null
+++ b/test/net/sf/briar/LockFairnessTest.java
@@ -0,0 +1,81 @@
+package net.sf.briar;
+
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+
+public class LockFairnessTest extends TestCase {
+
+	@Test
+	public void testWritersDoNotStarevWithFairLocks() throws Exception {
+		// Create a fair fair read-write lock
+		ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
+		// Create a ton of reader threads that repeatedly acquire the read lock,
+		// sleep for a few ms and release the lock
+		Thread[] readers = new Thread[20];
+		for(int i = 0; i < readers.length; i++) {
+			readers[i] = new ReaderThread(lock);
+		}
+		// Stagger the start times of the readers so they release the read lock
+		// at different times
+		for(int i = 0; i < readers.length; i++) {
+			readers[i].start();
+			Thread.sleep(7);
+		}
+		// Create a writer thread, which should be able to acquire the lock
+		WriterThread writer = new WriterThread(lock);
+		writer.start();
+		Thread.sleep(1000);
+		// The writer should have acquired the lock
+		assertTrue(writer.acquiredLock);
+		// Stop the readers
+		for(int i = 0; i < readers.length; i++) readers[i].interrupt();
+	}
+
+	private static class ReaderThread extends Thread {
+
+		private final ReentrantReadWriteLock lock;
+
+		private ReaderThread(ReentrantReadWriteLock lock) {
+			this.lock = lock;
+		}
+
+		@Override
+		public void run() {
+			try {
+				while(true) {
+					lock.readLock().lock();
+					try {
+						Thread.sleep(13);
+					} finally {
+						lock.readLock().unlock();
+					}
+				}
+			} catch(InterruptedException quit) {
+				return;
+			}
+		}
+	}
+
+	private static class WriterThread extends Thread {
+
+		private final ReentrantReadWriteLock lock;
+		private volatile boolean acquiredLock = false;
+
+		private WriterThread(ReentrantReadWriteLock lock) {
+			this.lock = lock;
+		}
+
+		@Override
+		public void run() {
+			lock.writeLock().lock();
+			try {
+				acquiredLock = true;
+			} finally {
+				lock.writeLock().unlock();
+			}
+		}
+	}
+}