接口定义:
package com.zl.step17;
/**
* 定义了锁的基本操作
* 加锁()
* 解锁()
*
*/
public interface Lock {
// 加锁
void lock() throws InterruptedException;
// 解锁
void unlock();
}
package com.zl.step17;
public interface ReadWriteLock {
// 读锁
Lock readLock();
// 写锁
Lock writeLock();
// 获取当前有多少个线程正在执行写操作 最多1个
int getWritingWriters();
// 获取当前有多少线程正在等待获取写入锁 由于写锁导致阻塞
int getWaitingWriters();
// 等待当前有多少线程正在等待获取读锁
int getReadingReaders();
// 工厂方法创建ReadWriteLock
static ReadWriteLock readWriteLock() {
return new ReadWriteLockImpl();
}
// 工厂方法,创建ReadWriteLock ,并传入preferWriter
static ReadWriteLock readWriteLock(boolean preferWriter) {
return new ReadWriteLockImpl(preferWriter);
}
}
程序实现
package com.zl.step17;
// 设置为包可见
class ReadLock implements Lock {
private final ReadWriteLockImpl readWriteLock ;
ReadLock(ReadWriteLockImpl readWriteLock ){
this.readWriteLock = readWriteLock ;
}
@Override
public void lock() throws InterruptedException {
// 使用MUTEX作为锁
synchronized (readWriteLock.getMUTEX()){
// 若此时有线程正在进行写操作,或者有写线程在等待并且偏向写锁的标识为ture,就无法获取读锁,只能挂起
while(readWriteLock.getWritingWriters() > 0 || (readWriteLock.getPreferWriter() && readWriteLock.getWaitingWriters() >0 )){
readWriteLock.getMUTEX().wait();
}
// 成功获取读锁,并且使readingReader的数量增加
readWriteLock.increamentReadingReaders();
}
}
@Override
public void unlock() {
//使用Mutex作为锁,并且进行同步
synchronized (readWriteLock.getMUTEX()){
// 释放锁的过程就是使得当前reading的数量减一
// 将perferWriter设置为true , 可以使得writer线程获得更多的机会
// 通知唤醒与Mutex唤醒monitor waitset中的线程
readWriteLock.decrementReadingReaders();
readWriteLock.changePrefer(true);
readWriteLock.getMUTEX().notifyAll();
}
}
}
package com.zl.step17;
// 设计为包可见
class WriteLock implements Lock {
private final ReadWriteLockImpl readWriteLock ;
WriteLock(ReadWriteLockImpl readWriteLock ){
this.readWriteLock = readWriteLock ;
}
@Override
public void lock() throws InterruptedException {
synchronized (readWriteLock.getMUTEX()){
try{
// 等待获取写入锁的数字加一
readWriteLock.increamentWaitingWriters();
// 如果此时有其他线程正在进行读操作,或者写操作,那么当前线程将被挂起
while (readWriteLock.getReadingReaders() > 0 || readWriteLock.getWritingWriters()>0 ){
readWriteLock.getMUTEX().wait();
}
}finally {
// 成功取得到写入锁,使得等待获取写入锁的计数器减一
this.readWriteLock.decrementWaitingWriters();
}
readWriteLock.incrementWritingWriters();
}
}
@Override
public void unlock() {
synchronized (readWriteLock.getMUTEX()){
// 减少正在写入锁的线程计数器
readWriteLock.decrementWritingWriters();
// 将偏好状态修改为false ,可以使得读锁会更快的获得
readWriteLock.changePrefer(false);
//唤醒其他线程
readWriteLock.getMUTEX().notifyAll();
}
}
}
package com.zl.step17;
// 对包可见的类
class ReadWriteLockImpl implements ReadWriteLock {
// 定义对象所
private final Object MUTEX = new Object();
// 当前有多少个线程正在执行写操作 最多1个
private int writingWriters = 0 ;
// 当前有多少线程正在等待获取写入锁 由于写锁导致阻塞
private int waitingWriters = 0 ;
// 等待当前有多少线程正在等待获取读锁
private int readingReaders = 0 ;
//read 和 writer 的偏好设置
private boolean preferWriter ;
public ReadWriteLockImpl(){
this(true);
}
public ReadWriteLockImpl(boolean preferWriter) {
this.preferWriter = preferWriter ;
}
@Override
public Lock readLock() {
return new ReadLock(this);
}
@Override
public Lock writeLock() {
return new WriteLock(this);
}
// 写线程增加
void incrementWritingWriters() {
this.writingWriters++ ;
}
// 等待写入线程增加
void increamentWaitingWriters(){
this.waitingWriters++ ;
}
// 读线程的数量增加
void increamentReadingReaders(){
this.readingReaders++ ;
}
// 写入线程数量减少
void decrementWritingWriters() {
this.writingWriters-- ;
}
// 写入等待线程减少
void decrementWaitingWriters(){
this.waitingWriters-- ;
}
// 读取线程减少
void decrementReadingReaders(){
this.readingReaders-- ;
}
// 获取当前有多少线程正在进行写操作
@Override
public int getWritingWriters() {
return this.writingWriters;
}
// 获取当前有多少个线程正在等待获取写入锁
@Override
public int getWaitingWriters() {
return this.waitingWriters ;
}
// 获取当前有多少读取线程
@Override
public int getReadingReaders() {
return this.readingReaders;
}
// 获取对象锁
Object getMUTEX(){
return this.MUTEX ;
}
// 获取当前是否偏向写锁
boolean getPreferWriter(){
return this.preferWriter ;
}
// 设置写锁偏好
void changePrefer(boolean preferWriter){
this.preferWriter = preferWriter ;
}
}
package com.zl.step17;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 对数据的书写操作
*/
public class ShareData {
// 定义共享数据(资源)
private final List<Character> container = new ArrayList<>() ;
// 构造ReadWriteLock
private final ReadWriteLock readWriteLock = ReadWriteLock.readWriteLock();
// 创建读取锁
private final Lock readLock = readWriteLock.readLock();
// 创建写入锁
private final Lock writeLock = readWriteLock.writeLock();
private final int length ;
public ShareData(int length){
this.length = length ;
for (int i = 0 ;i < length ; i++) {
container.add(i,'c') ;
}
}
public char[] read() throws InterruptedException{
try{
// 首先使用读锁进行lock
readLock.lock();
char[] newBuffer = new char[length] ;
for (int i= 0 ; i < length ; i++) {
newBuffer[i] = container.get(i) ;
}
slowly();
return newBuffer ;
}finally {
// 当操作结束之后,将锁释放
readLock.unlock();
}
}
public void write(char c ) throws InterruptedException{
try{
// 使用锁进行lock
writeLock.lock();
for (int i = 0 ; i<length ; i++) {
this.container.add(i,c) ;
}
slowly();
}finally {
// 当所有操作结束之后,将锁释放
writeLock.unlock();
}
}
private void slowly() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
读写锁使用
创建了10个读的线程和两个写的线程
package com.zl.step17;
import static java.lang.Thread.currentThread;
public class ReadWriteLockTest {
private final static String text = "Disconnected from the target VM, address: '127.0.0.1:60936', transport: 'socket'" ;
public static void main(String[] args) {
final ShareData shareData = new ShareData(50) ;
for (int i = 0 ; i< 2 ; i++) {
new Thread(()->{
for (int index =0 ; index < text.length() ; index++) {
try {
char c = text.charAt(index) ;
shareData.write(c);
System.out.println(currentThread()+" write " + c );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
for (int i = 0 ; i< 5 ; i++) {
new Thread(()->{
for (int index =0 ; index < text.length() ; index++) {
while (true) {
try {
String data = new String(shareData.read()) ;
System.out.println(currentThread()+" read " + data );
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
}