Java多线程编程核心技术-----第四章读书笔记
4.1.1
原:调用ReentrantLock对象的lock()方法获取锁,调用unlock()方法释放锁。P201
Lock lock = new ReentrantLock();
如果不调用lock.unlock()释放锁,那么即使线程任务结束,仍然不会释放锁。抛出异常也不会释放锁。
4.1.2
原:调用lock.lock()代码的线程就持有了“对象监视器”,其它线程只有等待锁被释放时再次争抢。P204
4.1.3
Condition对象通过ReentrantLock对象生成。Condition condition = lock.newCondition();
Condition的await()方法让持有lock锁的对象暂停,并释放同步锁。
4.1.4
另外一个线程获取到同步锁,采用condition.signal()唤醒暂停休眠的线程。
但值得注意的是,与notify()方法一样,刚苏醒的线程需要等待其它线程执行完毕,释放锁后,才能继续执行。
condtion在调用await()方法和signal()方法之前,需要先调用lock.lock(),保证在同步环境中才可执行。
condition.signal();一次只唤醒一个暂停的线程。
4.1.6
一个ReentrantLock对象可以生成多个Condition对象。
哪个线程中的condition对象调用了await()方法,
在别的线程中调用同一个condition的signal()方法唤醒的就是哪个线程。
4.1.9
ReentrantLock的构造函数接收一个 boolean 类型的数值。
Lock lock = new ReentrantLock(boolean b);
如果boolean为true,那么此锁就是公平锁。
哪个线程先进入可执行状态,哪个线程优先获取 lock.lock()的锁。
默认为false,就是常规的非公平锁。进入可执行状态的线程,进行争夺同步锁。默认是非公平锁
4.1.10
ReentrantLock的getHoldCount(),作用是当前线程中调用了几次lock.lock()。
有点像锁重入的意思,当前线程调用的方法内部调用另外一个方法,那个方法也
需要同步锁,需要调用lock.lock(),那么是可以进入的。
ReentrantLock的lock.getQueueLength() 返回同步队列的长度
ReentrantLock的lock.getWaitQueueLength(Condition) 返回指定condition对象的等待队列的长度
4.1.11
ReentrantLock的lock.hasQueuedThread(Thread thread) 查看是否有指定的thread在等待当前的线程释放lock锁
ReentrantLock的lock.hasQueuedThreads() 查看是否有其它线程在等待当前的线程释放锁。
ReentrantLock的lock.hasWaiters(Condition condition) 当前lock是否有condition让其它线程等待了
4.1.12
ReentrantLock的isFair()判断是否是公平锁
ReentrantLock的isHeldByCurrentThread()判断当前线程是否保持锁定,很有用,判断当前线程是否还有锁。
4.1.13
lock.lock();获取同步
lock.lockInterruptibly();获取同步,并检测线程中断状态位,一旦线程中断,则抛出异常而释放锁。所以有try-catch语句监控
if(lock.tryLock()){ A代码; }else{ B代码; } 如果获取不到同步锁,那么就执行B了,不然干等等到什么时候。
if(lock.tryLock(3,TimeUnit.SECONDS)){ A代码; }else{ B代码; } 如果等了3秒还没有锁,那么执行B代码。
tryLock可以用于获取数据库连接。等待多少秒连接池没有连接,那么就创建一个。
4.1.14
ReentrantLock的生成的Condtion对象的condition.awaitUninterruptibly(),
它让线程在睡眠期间即使线程被中断,也不报中断异常。当然了,锁跟await()一样,会释放。
Thread.sleep方法,是被try-catch进行监控的,一旦线程中断状态位被置为true,则抛中断异常,并释放同步锁。
注意:lock锁,即使抛出异常也不放,必须执行lock.unlock()才能释放同步锁。
4.2
ReentrantReadWriteLock是读写锁。
原:多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。P236
原:多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写入操作。P236
4.2.1
创建读写锁
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
获取读锁并开启
lock.readLock().lock();
同样的,也要释放
lock.readLock().unlock();
创建写锁并开启
lock.writeLock().lock();
有一个方法,获取了写锁,并lock.writeLock().lock();
在此写锁执行任务完毕,若不执行 lock.writeLock().unlock();其它线程都要等待
原:读写,写读,写写 都是互斥的,而 读读 是非互斥,是异步的。P240
---------------------------------------------------
ReentranceLock 等 同步组件,内部都用了 队列同步器AQS 实现。
队列同步器(简称:同步器)AbstractQueuedSynchronizer(英文简称:AQS)
它使用了一个 int 成员变量表示同步状态,通过内置的 先进先出Node队列来完成资源获取和线程的排队工作。
队列同步器中的int成员变量的作用是:标记共享变量的状态(是否已经被其他线程锁住等)
先进先出的队列用来存储没有获得到同步锁的线程。
一般我们在一个同步类中,使用 嵌套类 来 继承 队列同步器AQS。同步器既可以支持独占式地获取同步状态,也可以支持共享式地获取同步状态,这样就可以方便实现不同类型的同步组(ReentrantLock、ReentrantReadWriteLock)
同步组件的锁是给客户端用的。而同步器是锁的内部类,AQS是同步器的父类,提供了操作同步状态、线程管理的相关操作
.