Java并发编程与技术内幕:聊聊锁的技术内幕(中)
来源:互联网 发布:布料模拟软件 编辑:程序博客网 时间:2024/06/07 06:24
摘要:本文主要讲了读写锁。
一、读写锁ReadWriteLock
在上文中回顾了并发包中的可重入锁ReentrantLock,并且也分析了它的源码。从中我们知道它是一个单一锁(笔者自创概念),意思是在多人读、多人写、或同时有人读和写时。只能有一个人能拿到锁,执行代码。但是在很多场景。我们想控制它能多人同时读,但是又不让它多人写或同时读和写时。(想想这是不是和数据库的可重复读有点类型?),这时就可以使用读写锁:ReadWriteLock。
下面来看一个应用
package com.lin;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock;public class ReadWriteLockTest { public static void main(String[] args) { //创建一个锁对象 ,非公平锁 ReadWriteLock lock = new ReentrantReadWriteLock(false); //创建一个线程池 ExecutorService pool = Executors.newCachedThreadPool(); //设置一个账号,设置初始金额为10000 Account account = new Account(lock,"123456",10000); //账号取钱10次,存钱10次,查询20次 for(int i=1;i<=10;i++) { Operation operation1 = new Operation(account,"take"); Operation operation2 = new Operation(account,"query"); Operation operation3 = new Operation(account,"save"); Operation operation4 = new Operation(account,"query"); pool.execute(operation1); pool.execute(operation2); pool.execute(operation3); pool.execute(operation4); } pool.shutdown(); while(!pool.isTerminated()){ //wait for all tasks to finish } System.out.println("账号"+ account.getAccoutNo() +",最后金额为:"+account.getMoney()); }}class Operation implements Runnable{private Account account;//账号private String type;Operation(Account account,String type){this.account = account;this.type = type;}public void run() { if ("take".equals(type)) { //每次取100元 //获取写锁 account.getLock().writeLock().lock(); account.setMoney(account.getMoney() -100); System.out.println( "取走100元,账号"+ account.getAccoutNo()+" 还有"+account.getMoney()+"元"); account.getLock().writeLock().unlock(); } else if ("query".equals(type)) { //获取写锁 account.getLock().readLock().lock(); System.out.println( "查询账号"+ account.getAccoutNo()+" 还有"+account.getMoney()+"元"); account.getLock().readLock().unlock(); } else if ("save".equals(type)) { //获取写锁 account.getLock().writeLock().lock(); account.setMoney(account.getMoney() + 100); System.out.println( "存入100元,账号"+ account.getAccoutNo()+" 还有"+account.getMoney()+"元"); account.getLock().writeLock().unlock(); }}}class Account {private int money;//账号上的钱private ReadWriteLock lock;//读写写private String accoutNo;//账号Account(ReadWriteLock lock,String accoutNo,int money) {this.lock = lock;this.accoutNo = accoutNo;this.money = money;}public int getMoney() {return money;}public void setMoney(int money) {this.money = money;}public ReadWriteLock getLock() {return lock;}public void setLock(ReadWriteLock lock) {this.lock = lock;}public String getAccoutNo() {return accoutNo;}public void setAccoutNo(String accoutNo) {this.accoutNo = accoutNo;}}输出结果:
在上面的例子中,设置了一个账号。金额为10000,然后开了10条线程每次取100,10条线程每次存100,20条线程一直查。从结果中我们可以看到是正确的。
二、源码分析
1、ReadWriteLock
public interface ReadWriteLock { Lock readLock();//返回读锁 Lock writeLock();//返回写锁}
ReadWriteLock就只是一个接口类,真正实现 类在ReentrantReadWriteLock
2、ReentrantReadWriteLock
(1)包含变量
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { private static final long serialVersionUID = -6992448646407690164L; /**读锁*/ private final ReentrantReadWriteLock.ReadLock readerLock; /** 写锁 */ private final ReentrantReadWriteLock.WriteLock writerLock; /** 内部类,在ReentrantLock也有它 */ final Sync sync;
看了一个它的变量还是比较简单的,其中Sync类在ReentrantLock类中笔者已介绍过。
(2)构造函数
public ReentrantReadWriteLock() { this(false); } /** * 设置读写锁 */ public ReentrantReadWriteLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync();//是否公平 readerLock = new ReadLock(this); writerLock = new WriteLock(this); }
看了看FairSync的源码其实和上节中讲的基本一样。这里就不再展开。
(3)ReadLock
看了下读锁,其实很简单,发现里面封装的都 是调用Sync类的方法,看来它才是重点。在ReadLock类的lock方法中,我们看到了sync.acquireShared(1);这里就可以认为是一个共享锁
public static class ReadLock implements Lock, java.io.Serializable { private static final long serialVersionUID = -5992448646407690164L; private final Sync sync; //和上面的一样,是同一个类
protected ReadLock(ReentrantReadWriteLock lock) { sync = lock.sync; } public void lock() { sync.acquireShared(1); //共享锁 } public void lockInterruptibly() throws InterruptedException { sync.acquireSharedInterruptibly(1);//响应中断,跳出阻塞 } public boolean tryLock() { return sync.tryReadLock();//取得锁才返回true } public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); } public void unlock() { sync.releaseShared(1);//释放锁 }
再进来看看
public final void acquireShared(int arg) { if (tryAcquireShared(arg) < 0) doAcquireShared(arg); }
再进去就看不了,这里的方法其实就是认为取得一个共享锁。
public static class WriteLock implements Lock, java.io.Serializable { private static final long serialVersionUID = -4992448646407690164L; private final Sync sync; protected WriteLock(ReentrantReadWriteLock lock) { sync = lock.sync; } public void lock() { sync.acquire(1); //表明只是取得一个锁,但不是独占 } public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); }在WriteLock锁中的lock方法和ReadLock是有所不同的。WriteLock它是一个独占锁。也就是有线程拿到后,其它线程就得阻塞等待了。
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
0 0
- Java并发编程与技术内幕:聊聊锁的技术内幕(中)
- Java并发编程与技术内幕:聊聊锁的技术内幕(中)
- Java并发编程与技术内幕:聊聊锁的技术内幕(中)
- Java并发编程与技术内幕:聊聊锁的技术内幕(上)
- Java并发编程与技术内幕:聊聊锁的技术内幕(上)
- Java并发编程与技术内幕:聊聊锁的技术内幕(上)
- Java并发编程与技术内幕
- Java并发编程与技术内幕:线程池深入理解
- Java并发编程与技术内幕:Callable、Future、FutureTask、CompletionService
- Java并发编程与技术内幕:ThreadGroup线程组应用
- Java并发编程与技术内幕:ThreadFactory、ThreadLocal
- Java并发编程与技术内幕:ThreadFactory、ThreadLocal
- Java并发编程与技术内幕:ConcurrentHashMap源码解析
- Java并发编程与技术内幕:CopyOnWriteArrayList、CopyOnWriteArraySet源码解析
- Java并发编程与技术内幕:线程池深入理解
- Java并发编程与技术内幕:Callable、Future、FutureTask、CompletionService
- Java并发编程与技术内幕:线程池深入理解
- Java并发编程与技术内幕:消费者-生产者模式研究
- Java GZip数据压缩传输到前台
- 源码分析-java-AbstractList-Itr和ListItr的实现
- 工厂方法设计模式
- LeetCode - 120. Triangle
- 安装和使用Oracle VM VirtualBox中的要点,注意事项和遇到的问题
- Java并发编程与技术内幕:聊聊锁的技术内幕(中)
- L1-032. Left-pad
- Maven导出Project依赖的jar包
- 交换机、路由器、集线器的区别
- win7下安装配置spark
- 软件测试总体方案
- shopnc点击加入购物车流程
- The method list(String, Object[]) is ambiguous for the type BaseHibernateDao<M,PK
- 软件测试测试方案