所有的锁其实就是个同步手段,从jdk1.7来看,都是依靠AbstractQueuedSynchronizer(AQS)实现的,这个东西之前的文章讲过,在这个类里有两种锁,一种是共享锁(作用是让多个线程可以同时拥有锁,也就是允许多个线程同时访问一个共享资源),一种是独占锁(某一时刻只能一个线程可以拥有锁,也就是只允许一个线程访问共享资源)。AQS留出一个方法让用户实现,对于独占锁是tryAcquire,对于共享锁是tryAcquireShared,目的就是让用户来决定什么状态下(没获得锁)需要将线程加入等待队列并阻塞该线程和什么状态下(获得锁)让线程继续往下执行。
对于独占锁,目前有ReentrantLock,Semaphore(1)
对于共享锁,目前有ReentrantReadWriteLock,Semaphore(n)(n>1),CountDownLatch,CyclicBarrierReentrantLock
两个特点:
其一,是他是一种可重入锁,也就是同一个线程在拥有这个锁的情况下可以再次获得该锁,实现比较简单,就是获得锁的时候记录一下获得所得线程,等再次去尝试获得锁的时候要先看看是不是获得锁的线程和当前线程一样,如果是的话就可以继续获得锁,并将锁的使用计数加1,相反释放时也会减一,减到零之后别的线程才能获得该锁。
其二,是它里面有公平锁和非公平锁之分,需要在创建对象时指定,默认为非公平锁。非公平锁就是尝试获得锁的时候如果该锁可获得,那该线程马上获得锁并往下执行,不care等待该锁的其他线程,当然了如果有其他线程等待该锁,那么该线程也不一定能获得该锁,也可能之前等待的线程获得锁,而对于公平锁,就是尝试获得锁的时候如果该锁可获得,那该线程会查看是否有其他线程先于它在等着该锁,如果有,要让出该锁给其他线程,自己加入等待队列,这比较公平,有先来后到~
Semaphore
当他的初始参数为1时也就是类似独占锁了,他也有公平锁和非公平锁之分,但他不能重入(如果初始化参数大于1,还是可以达到重入的效果的,重入次数有初始化参数决定)。
ReentrantReadWriteLock
和ReentrantLock有类似之处,可重入,有公平锁和非公平锁之分,不同之处:它是读写锁,有读锁和写锁之分,读锁之间不会阻塞,读锁和写锁或写锁和写锁会阻塞。
4.Semaphore(n)(n>1)
允许n个线程获得锁,超出n个就阻塞,非可重入。
5.CountDownLatch
该锁适用于n个线程等待另外m个线程释放锁之后才开始执行,CountDownLatch(int count)方法初始化count,比如count为m,则需要有m个线程调用countDown方法后,即count减小至0,调用await方法的线程才能继续执行。
6.CyclicBarrier
该锁是让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(int
parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。CyclicBarrier还提供一个更高级的构造函数CyclicBarrier(int parties, Runnable barrierAction),用于在线程到达屏障时,优先执行barrierAction,方便处理更复杂的业务场景。其实就是CyclicBarrier里有个count计数,每次调用await都会减一,减到零,回去先执行barrierAction,然后所有被await阻塞的线程再同时开始执行。