前言
为什么要用java来实现?
因为php就是一个残缺的语言!因为对于并发而言,最重要的原子操作。其中并发和阻塞基本上实现都是借助于硬件的实现。而信号量就是基本上每个操作系统都提供的api。
什么是读写锁
其实读写锁分为两种。一个是读优先,一个是写优先。
什么是信号量
信号量最主要的是P操作和V操作。
P操作
semaphore减1。当semaphore小于0时,此时线程阻塞。
V操作
semaphore就会加1。如果小于等于0,唤醒一个等待线程。
实现一个互斥锁。
互斥锁,是在某一个时刻,只有一个线程可以运行。
将semaphore初始值设为1。
当semaphore执行获取锁时,semaphore减1。semaphore为0,当下一个线程想要获取锁时,semaphore再减1。此时semaphore小于0时,线程阻塞。
当释放锁时,semaphore就会加1。并且唤醒一个等待线程。
public class MutexLock {
private Semaphore mutex = new Semaphore(1);
public void lock() throws InterruptedException{
mutex.acquire();
}
public void unlock(){
mutex.release();
}
}
实现读写锁
实现步骤
- 在ReadLock和WriteLock都加上一个写锁。这样保证读操作还是写操作同时只有一个线程可以进行。
- 读写锁,是可以允许重复读的。所以添加一个readCound计数。表示当前有多少读线程。因为readCount是共享变量。所以用countMutex进行保护。
- 当readCount等于0时,表示第一个读线程。尝试获取锁。如果拿到写锁,readCount++。下一个读线程就不用获取锁。如果没有获取锁,则readCount一直是0。读线程处于等待状态。
- 离开时,只有所有的读结束,才释放锁。唤醒一个等待线程。一般是写线程。
具体实现
public class ReadWriteLock {
private int readCount = 0;
private MutexLock countMutex = new MutexLock();
private MutexLock writeMutex = new MutexLock();
public class ReadLock{
public void lock() throws InterruptedException{
//readCount是共享变量,所以需要实现一个锁来控制读写
//synchronized(ReadWriteLock.class){} countMutex.lock();
//只有是第一个读者,才将写锁加锁。其他的读者都是进行下一步
if(readCount == 0){
writeMutex.lock();
}
++readCount;
countMutex.unlock();
}
public void unlock() throws InterruptedException{
countMutex.lock();
readCount--;
//只有当读者都读完了,才会进行写操作
if(readCount == 0){
writeMutex.unlock();
}
countMutex.unlock();
}
}
public class WriteLock{
public void lock() throws InterruptedException{
writeMutex.lock();
}
public void unlock(){
writeMutex.unlock();
}
}
}
测试代码
public class Main {
private static ReadWriteLock readWriteLock = new ReadWriteLock();
private static ReadWriteLock.ReadLock readLock = readWriteLock.new ReadLock();
private static ReadWriteLock.WriteLock writeLock = readWriteLock.new WriteLock();
public static void main(String[] args){
test();
}
private static void test(){
Thread t;
int writeNum = (int)(Math.random() * 10);
for(int i = 0; i < 10; i++){
// if(i == writeNum){
if((int)(Math.random() * 10) > 5){
t = new Thread(){
public void run(){
try{
writeLock.lock();
System.out.println(this.getName() + " writing");
Thread.sleep(
(int)(Math.random() * 6 * 1000));
System.out.println(this.getName() + " write done");
writeLock.unlock();
}catch (Exception e){}
}
};
}else{
t = new Thread(){
public void run(){
try{
readLock.lock();
System.out.println(this.getName() + " reading");
Thread.sleep(
(int)(Math.random() * 3 * 1000));
System.out.println(this.getName() + " read done");
readLock.unlock();
}catch (Exception e){}
}
};
}
t.setName("thread " + i);
t.start();
}
}
}
结果
图片上传不了,就直接贴出来。某一次测试结果如下
thread 2 writing
thread 2 write done
thread 4 writing
thread 4 write done
thread 9 writing
thread 9 write done
thread 0 reading
thread 6 reading
thread 8 reading
thread 7 reading
thread 5 reading
thread 0 read done
thread 6 read done
thread 5 read done
thread 8 read done
thread 7 read done
thread 3 writing
thread 3 write done
thread 1 writing
thread 1 write done
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。