Java多线程学习记录(二)

14

读写锁

伪代码

一个通用的读写锁的伪代码如下所示

count_mutex = mutex_init();
write_mutex = mutex_init();
read_count = 0;

void read_lock {
 lock(count_mutex);
 read_count++;
 if (read_count == 1) {
  lock(write_mutex);
 }
 unlock(count_mutex);
}

void read_unlock {
 lock(count_mutex);
 read_count--;
 if (read_count == 0) {
  unlock(write_mutex);
 }
 unlock(count_mutex);
}

void write_lock {
 lock(write_mutex);
}

void write_unlock {
 unlock(write_mutex);
}
void read_lock {
 lock(count_mutex);
 read_count++;
 if (read_count == 1) {
  lock(write_mutex);
 }
 unlock(count_mutex);
}

lock(count_mutex) 的主要作用是保证read_count的计数访问

当read_count 是1的时候,锁住写者

void read_unlock {
 lock(count_mutex);
 read_count--;
 if (read_count == 0) {
  unlock(write_mutex);
 }
 unlock(count_mutex);
}

与上面的操作相反,如果当read_count-- 之后read_count 是0的时候,说明本线程是最后一位读者,所以在解锁读者锁之前要解锁写者锁。

读写锁的特性

一般来说,读取一个资源的并发操作由以下三个:

  1. 读读

  2. 读写

  3. 写写

假设只使用互斥锁的话,以上三个操作都会被阻塞,读写锁实际上就是为了解决这个问题,在大部分资源并发的操作下,操作1实际上是最普遍而且不会产生并发问题的操作,可以理解为读写锁是比互斥锁更乐观的锁,它保证读读可以并发,提高了并发编程的性能。

ReentrantReadWriteLock

Java的读写锁实现为ReentrantReadWriteLock,具体用法如下所示

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockExample {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private int sharedResource = 0;

    public int read() {
        lock.readLock().lock();
        try {
            return sharedResource;
        } finally {
            lock.readLock().unlock();
        }
    }

    public void write(int value) {
        lock.writeLock().lock();
        try {
            sharedResource = value;
        } finally {
            lock.writeLock().unlock();
        }
    }
}