Java中的锁使用与实现

1.Lock接口锁是用来控制多个线程访问共享资源的方式,通常来讲,一个锁可以防止多个线程同时访问共享资源。 在Lock出现以前,java程序是靠synchronized关键字实现锁功能的,而Java SE5以后,并发包中新增了Lock接口用来实现锁功能。它提供了与synchronized关键字相似的同步功能,只是在使用时须要显示地获取和释放锁。有用了锁获取与释放的可操做性、可中断的获取锁以及超时获取锁等synchronized关键字所不具有的同步特性。 Lock接口提供的synchronized关键字所不具有的主要特性 1.尝试非阻塞地获取锁。 2.能被中断的获取锁。获取到锁的线程可以响应中断,当获取到锁的线程被中断,当获取到锁的线程被中断时,中断异常将会被抛出,同时锁会释放。 3.超时获取锁 在指定的时间以前获取锁,若是截止时间到了仍旧没法获取锁,则返回。java

2.AQS 队列同步器AbstractQueuedSynchronizer,用来构建锁或者其余同步组建的基础框架。用一个int类型的state成员变量表示同步状态,经过内置的FIFO队列来完成资源获取线程的排队工做。 同步器的主要使用方法是继承,子类经过继承同步器(AQS)并实现它的抽象方法来管理同步状态,在抽象方法的实现过程当中免不了进行状态更改。须要同步器提供三个方法getState(),setState()和compareAndSetState()来进行操做,由于他们可以保证状态的改变是安全的。子类推荐被定义为自定义同步组件的静态内部类,同步器自身没有实现任何同步接口。它仅仅是定义了若干同步状态获取和释放的方法来提供同步组件使用。同步器既能够支持独占式地获取同步状态,也能够支持共享地获取同步状态。这样能够实现不一样类型的同步组件(ReentrantLock、ReentrantReadWriteLock和CountDownLatch等)。 队列同步器的接口与示例 同步器的设计是基于模板方法的,也就是说,使用者须要继承同步器并从新指定的方法,随后将同步器组合在自定义同步组件的实现中,并调用同步器提供的模板方法,而这些模板方法将会调用使用者重写的方法。 重写同步器指定的方法时,须要使用同步器提供的以下3个方法来访问或者修改同步状态。 a) getState() b) setState(int newState) 设置当前同步状态 c) compareAndSetState(int except,int update):使用CAS设置当前状态,改方法可以保证状态设置的原子性。安全

同步器可重写的方法与描述 boolean tryAcquire(int arg) 独占式获取同步状态 boolean tryRelease(int arg) 独占式释放同步状态 int tryAcquireShared(int arg) 共享式获取同步状态 boolean tryReleaseShared(int arg) 共享式释放同步状态 boolean isHeldExcusively() 当前同步器是否在独占模式下被线程占用并发

实现自定义同步组件时,将会提供同步器提供的模板方法,这些模板方法描述以下 void acquire(int arg) 独占式获取同步状态,若是当前线程获取同步状态成功,则由改方法返回,不然,进入同步队列等待。 void acquireInterruptibly(int arg) 与acquire(int arg)相同,可是该方法响应中断。 boolean tryAcquireNanos(int arg,long nanos) 在anquireInterruptibly(int arg)基础上增长了超时限制 void acquireShared(int arg) 共享获取同步状态,若是当前线程获取同步状态成功,则由改方法返回,不然,进入同步队列等待。 void acquireSharedInterruptibly(int arg) 与acquireShared(int arg)相同,可是该方法响应中断。 boolean tryAcquireSharedNanos(int arg,long nanos) 在anquireSharedInterruptibly(int arg)基础上增长了超时限制 boolean release(int arg)独占式的释放同步状态,该方法会在释放同步状态以后,将同步队列中的第一个节点中包含的线程唤醒。 boolean releaseShared(int arg) 共享式的释放同步状态框架

Collection<Thread> getQueuedThreads() 获取等待队列上的线程集合ui

同步器提供的模板方法基本分为三类:独占模式获取与释放同步状态、共享式获取与释放同步状态和查询同步队列的等待线程状况。线程

class Mutex implments Lock { private static class Sync extends AbstractQueuedSynchronizer { //是否处于占用状态 protected boolean isHeldExclusively{ return getState()==1 } //当前状态为0的时候获取锁 public boolean tryAcquire(int acquires){ if(compareAndSwap(0,1)){ setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } //释放锁,将状态设置为0 protected boolean tryRelease(int release){ if(getState()==0) throw new IllegalMonitorStateException(); setState(0); setExclusiveOwnerThread(null); return true; } //返回一个Condition 每一个Condition都包含一个condition状态 Condition newCondition(){ return new ConditionObject(); } }设计

//仅须要将操做代理到Sunc上便可,使用模板方法 private final Sync sync=new Sync(); public void lock(){ sync.lock(); } public boolean tryLock(){ return sync.tryLock(); } ..... } 在Mutex中定义一个静态内部类代理

队列同步器的实现分析 1.同步队列 同步器依赖内部的同步队列(一个FIFO双向队列)来完成同步状态的管理,当前线程获取同步状态失败后时,同步器将会将当前线程以及等待状态等信息构形成为一个节点(Node)并将其加入同步队列,同时阻塞当前线程,当同步状态释放时,会把首节点中的线程唤醒,再次尝试获取同步状态。 2.独占式同步状态获取与释放 经过调用acquire(int arg)方法获取同步状态,该方法对中断不敏感,进入同步队列中,线程被中断后,线程不会从同步队列中移除。继承

3.共享式同步获取与释放 共享式获取与独占式获取最主要的区别在于同一时刻可否有多个线程同时获取同步状态。接口

4.独占式超时获取同步状态 经过调用同步器的doAcquireNanos(int arg,long nanosTimeout)方法能够超时得到同步状态,即在指定的时间段内获取同步状态。若是获取到同步状态返回tue,不然返回false. 响应中断的同步状态获取过程。在Java5以前,当一个线程获取不到锁而被阻塞在synchronizer以外时,对线程进行中断操做,此时改线程的中断标志位被修改,可是线程依旧会阻塞在synchronized上,等待着获取锁。在Java5中,同步器提供了acquireInterruptibly(int arg)方法,这个方法在等待获取同步锁状态时,若是当前线程被中断,会当即返回,并抛出InterruptException。 超时获取同步状态能够被视为响应中断获取同步状态过程的“加强版”,doAcquireNanos(int arg,long nanosTimeOut)方法在支持响应中断的基础上,增长了超时获取的特性。

相关文章
相关标签/搜索