Java-线程并发(一)-读写锁-ReentrantReadWriteLock

1、锁基本概念

  java并发为了线程安全需要对线程进行加锁,从而保证各线程安全地访问共享数据。但是加锁安全之后,又想提高加锁的效率。出现了共享锁和排它锁。

  • 共享锁:同一资源允许个线程对其进行操作,而且不会引起数据不安全(如脏数据、幻读等现象)
  • 排它锁:同一资源允许个线程对其进行操作,而且不会引起数据不安全

综上,共享锁的效率比排它锁高,但并不是所有场景都适用于共享锁。读写锁就是在某一场景下使用的;如一个文件可多个线程读,但只允许一个线程写。


2、读写锁概念

  • 同一时刻允许多个读锁占用(共享锁)
  • 同一时刻只允许一个线程占用(排它锁)


3、java内置读写锁(ReentrantReadWriteLock)

  ● ReentrantReadWriteLock特点
      ○ 公平性:先请求锁的线程先获得锁(相对的有非公平性锁)
      ○ 可重入:一个已获得锁的线程可以继续再向该资源加锁
      ○ 锁降级:写锁可降级到读锁,即持有写锁的线程可放弃写锁,变为读锁
      ○ 实现ReadWriteLock接口
          ■ readLock()
          ■ writeLock()
  ● 读写锁依赖自定义同步器来实现同步功能,而读写状态就是同步器的同步状态
      ○ 同步状态(记为S):表示锁被一个线程重复获取的次数
          ■ 高16位表示读,低16位表示写
          ■ 通过位运算实现
              ● 访问写状态:S&0x0000FFFF
              ● 修改写状态:S+1
              ● 访问读状态:S>>>16
              ● 修改读状态:S+(1<<16)
      ○ 判断哪种锁:S不等于0时,当写状态(S&0x0000FFFF)等于0时,则读状态(S>>>16)大于0,即读锁已被获取


4、读写锁实例

/**
 * 对hashMap进行读写操作,并保证HashMap线程安全
 * @author hejy
 *
 */
public class Cache {
	static HashMap<Integer,Object> map=new HashMap<Integer,Object>();
	ReentrantReadWriteLock rwl=new ReentrantReadWriteLock();
	Lock r=rwl.readLock();	//获取读锁
	Lock w=rwl.writeLock();	//获取写锁

	//读
	public Object get(int key) {
		r.lock();
		Object o=map.get(key);
		r.unlock();
		return o;
	}
	
	//写
	public void set(int key,Object o) {
		w.lock();
		map.put(key, o);
		w.unlock();
	}
	
	//清空锁
	public void clear() {
		w.lock();
		map.clear();
		w.unlock();
	}
	
	//读线程
	class Read extends Thread{
		int key;
		public Read(int key) {
			this.key=key;
		}
		
		@Override
		public void run() {
			// TODO Auto-generated method stub
//			System.out.println("read "+Thread.currentThread().getName());
			System.out.println("从HashMap读取:开始");
			System.out.println(get(key));
			System.out.println("从HashMap读取:结束");
		}
	}
	
	//写线程
	class Write extends Thread{
		int key;
		String str;
		
		public Write(int key,String str) {
			this.key=key;
			this.str=str;
		}
		
		@Override
		public void run() {
			// TODO Auto-generated method stub
//			System.out.println("write "+Thread.currentThread().getName());
			System.out.println("向HashMap写入:开始");
			set(key, str);
			System.out.println("向HashMap写入:结束");
			
		}
	}
	
	public static void main(String[] args) {
		Cache141 c=new Cache141();
		String str[]= {"a","b","c","d","e","f","g","h","i","j"};
		for (int i = 0; i < 5; i++) {
			c.new Write(i,str[i]).start();
			c.new Read(i).start();
		}
	}
}


5、源码分析-获取写锁(tryAcquire(intacquires))

  • 上面的“Lock w=rwl.writeLock(); //获取写锁对象,w.lock();则是获取写锁,下面一步步分析:
  • 执行w.lock()其实是执行:
public void lock() {
            sync.acquire(1);
        }
  • 可以看到其实是执行acquire(int arg)函数,该函数如下:
public final void acquire(int arg) {
	        if (!tryAcquire(arg) &&	//获取资源
	            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))	//加入等待队列
	            selfInterrupt();	//自我中断
	    }
  • 上面只对tryAcquire(int arg)函数分析【其他的函数在以后章节解析】,tryAcquire(int arg)是获取锁的意思,因为Lock接口对象指向WriteLock对象(写锁),所以这里是获取写锁
protected final boolean tryAcquire(int acquires) {
            Thread current = Thread.currentThread();	//当前线程
            int c = getState();	//获取状态
            int w = exclusiveCount(c);	//获取写状态
            if (c != 0) {	//状态不为0,则有锁
                // 如果写状态为0,则为读锁;
            	//否则写状态不为0,则为写锁,因为是重入锁,所以判断当前线程是否获写锁的线程
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;	//获锁失败
                //重入次数大于最大次数,MAX_COUNT=2^16-1
                if (w + exclusiveCount(acquires) > MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // 更新状态,这里的acquires=1
                setState(c + acquires);
                return true;	//获取成功
            }
            if (writerShouldBlock() ||	//该写锁是否应该阻塞
                !compareAndSetState(c, c + acquires))	//CAS操作是否成功
                return false;
            setExclusiveOwnerThread(current);	//当前线程获得锁
            return true;
        }


 
 
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 、可私信6博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 、可私信6博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值