package com.zhengweihao.test.concurrent.readwritelock;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import org.junit.Test;
public class ReadWriteLockTest {
private int runOver = 0;
private static final ExecutorService pool = Executors
.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private static final ReadLock readLock = rwl.readLock();
private static final WriteLock writeLock = rwl.writeLock();
/**
* 测试读锁不互斥
*/
@Test
public void testReadReadLock() {
runOver = 2;
final int sleepTime = 1000;
pool.execute(new Runnable() {
public void run() {
readLock.lock();
System.out.println("read1 locked " + nowString() + "..");
sleep(sleepTime);
System.out.println("read1 unlocked " + nowString() + "..");
runOver--;
readLock.unlock();
}
});
pool.execute(new Runnable() {
public void run() {
readLock.lock();
System.out.println("read2 locked " + nowString() + "..");
sleep(sleepTime);
System.out.println("read2 unlocked " + nowString() + "..");
runOver--;
readLock.unlock();
}
});
while (runOver > 0) {
sleep(sleepTime);
}
}
/**
* 测试读锁阻塞写锁
*/
@Test
public void testReadWriteLock() {
runOver = 2;
final int sleepTime = 1000;
pool.execute(new Runnable() {
public void run() {
readLock.lock();
System.out.println("read locked " + nowString() + "..");
sleep(sleepTime);
System.out.println("read unlocked " + nowString() + "..");
runOver--;
readLock.unlock();
}
});
pool.execute(new Runnable() {
public void run() {
writeLock.lock();
System.out.println("write locked " + nowString() + "..");
sleep(sleepTime);
System.out.println("write unlocked " + nowString() + "..");
runOver--;
writeLock.unlock();
}
});
while (runOver > 0) {
sleep(sleepTime);
}
}
/**
* 测试写锁阻塞读锁
*/
@Test
public void testWriteReadLock() {
runOver = 2;
final int sleepTime = 1000;
pool.execute(new Runnable() {
public void run() {
writeLock.lock();
System.out.println("write locked " + nowString() + "..");
sleep(sleepTime);
System.out.println("write unlocked " + nowString() + "..");
runOver--;
writeLock.unlock();
}
});
pool.execute(new Runnable() {
public void run() {
readLock.lock();
System.out.println("read locked " + nowString() + "..");
sleep(sleepTime);
System.out.println("read unlocked " + nowString() + "..");
runOver--;
readLock.unlock();
}
});
while (runOver > 0) {
sleep(sleepTime);
}
}
/**
* 测试写锁互斥
*/
@Test
public void testWriteWriteLock() {
runOver = 2;
final int sleepTime = 1000;
pool.execute(new Runnable() {
public void run() {
writeLock.lock();
System.out.println("write1 locked " + nowString() + "..");
sleep(sleepTime);
System.out.println("write1 unlocked " + nowString() + "..");
runOver--;
writeLock.unlock();
}
});
pool.execute(new Runnable() {
public void run() {
writeLock.lock();
System.out.println("write2 locked " + nowString() + "..");
sleep(sleepTime);
System.out.println("write2 unlocked " + nowString() + "..");
runOver--;
writeLock.unlock();
}
});
while (runOver > 0) {
sleep(sleepTime);
}
}
private void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private String nowString() {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
return sdf.format(date);
}
}
运行结果:
当同时运行两个加读锁的线程时,两个线程不互斥。运行结果为:
read2 locked 2016-01-03 12:09:13..
read1 locked 2016-01-03 12:09:13..
read2 unlocked 2016-01-03 12:09:14..
read1 unlocked 2016-01-03 12:09:14..
当先运行加读锁线程,再运行加写锁线程时,读锁将阻塞写锁。运行结果为:
read locked 2016-01-03 12:12:43..
read unlocked 2016-01-03 12:12:44..
write locked 2016-01-03 12:12:44..
write unlocked 2016-01-03 12:12:45..
当先运行加写锁线程,再运行加读锁的线程时,读锁等待写锁解锁。运行结果为:
write locked 2016-01-03 12:14:27..
write unlocked 2016-01-03 12:14:29..
read locked 2016-01-03 12:14:29..
read unlocked 2016-01-03 12:14:30..
当两个加写锁的线程先后运行,后者将等待前者解锁。运行结果为:
write1 locked 2016-01-03 12:16:05..
write1 unlocked 2016-01-03 12:16:06..
write2 locked 2016-01-03 12:16:06..
write2 unlocked 2016-01-03 12:16:07..
测试结果:
可见读写锁允许多个线程同时进行读操作;而当有读操作时进行写操作,写操作将等待读操作完成后再进行;当有写操作时,不论读或是写,都将被阻塞。这种程序就保证了有写操作时,不出现脏数据,同时也保证了较好的读性能,非常适合读多写少的架构。