全心代发17做网站,阿里邮箱企业登录入口,万彩动画大师,软件工程公司排名公平锁与非公平锁
ReentrantLock有一个很大的特点#xff0c;就是可以指定锁是公平锁还是非公平锁#xff0c;公平锁表示线程获取锁的顺序是按照线程排队的顺序来分配的#xff0c;而非公平锁就是一种获取锁的抢占机制#xff0c;是随机获得锁的#xff0c;先来的未必就一…
公平锁与非公平锁
ReentrantLock有一个很大的特点就是可以指定锁是公平锁还是非公平锁公平锁表示线程获取锁的顺序是按照线程排队的顺序来分配的而非公平锁就是一种获取锁的抢占机制是随机获得锁的先来的未必就一定能先得到锁从这个角度讲synchronized其实就是一种非公平锁。非公平锁的方式可能造成某些线程一直拿不到锁自然是非公平的了。看一下例子new ReentrantLock的时候有一个单一参数的构造函数表示构造的是一个公平锁还是非公平锁传入true就可以了
public class ThreadDomain42 {private Lock lock new ReentrantLock(true);public void testMethod() {try {lock.lock();System.out.println(ThreadName Thread.currentThread().getName() 获得锁);} finally {lock.unlock();}}}public static void main(String[] args) throws Exception {final ThreadDomain42 td new ThreadDomain42();Runnable runnable new Runnable() {public void run() {System.out.println(◆线程 Thread.currentThread().getName() 运行了);td.testMethod();}};Thread[] threads new Thread[5];for (int i 0; i 5; i)threads[i] new Thread(runnable);for (int i 0; i 5; i)threads[i].start();} 看一下运行结果 ◆线程Thread-0运行了 ◆线程Thread-3运行了 ThreadNameThread-0获得锁 ◆线程Thread-2运行了 ◆线程Thread-1运行了 ThreadNameThread-3获得锁 ◆线程Thread-4运行了 ThreadNameThread-2获得锁 ThreadNameThread-1获得锁 ThreadNameThread-4获得锁 我们的代码很简单一执行run()方法的第一步就是尝试获得锁。看到结果里面获得锁的顺序和线程启动顺序是一致的这就是公平锁。对比一下如果是非公平锁运行结果是怎么样的在new ReentrantLock的时候传入false ◆线程Thread-1运行了 ◆线程Thread-2运行了 ◆线程Thread-0运行了 ThreadNameThread-1获得锁 ThreadNameThread-2获得锁 ◆线程Thread-3运行了 ◆线程Thread-4运行了 ThreadNameThread-3获得锁 ThreadNameThread-0获得锁 ThreadNameThread-4获得锁 线程启动顺序是1 2 0 3 4获得锁的顺序却是1 2 3 0 4这就是非公平锁它不保证先排队尝试去获取锁的线程一定能先拿到锁 getHoldCount()
getHoldCount()方法返回的是当前线程调用lock()的次数看一下例子
public class ThreadDomain43 {private ReentrantLock lock new ReentrantLock();public void testMethod1() {try {lock.lock();System.out.println(testMethod1 getHoldCount lock.getHoldCount());testMethod2();} finally {lock.unlock();}}public void testMethod2() {try {lock.lock();System.out.println(testMethod2 getHoldCount lock.getHoldCount());} finally {lock.unlock();}}}public static void main(String[] args) {ThreadDomain43 td new ThreadDomain43();td.testMethod1();}
看一下运行结果 testMethod1 getHoldCount 1 testMethod2 getHoldCount 2 ReentrantLock和synchronized一样锁都是可重入的同一线程的同一个ReentrantLock的lock()方法被调用了多少次getHoldCount()方法就返回多少 getQueueLength()和isFair()
getQueueLength()方法用于获取正等待获取此锁定的线程估计数。注意估计两个字因为此方法遍历内部数据结构的同时线程的数据可能动态变化
isFair()用来获取此锁是否公平锁
看一下例子
public class ThreadDomain44 {public ReentrantLock lock new ReentrantLock();public void testMethod() {try {lock.lock();System.out.println(ThreadName Thread.currentThread().getName() 进入方法);System.out.println(是否公平锁 lock.isFair());Thread.sleep(Integer.MAX_VALUE);} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}}public static void main(String[] args) throws InterruptedException {final ThreadDomain44 td new ThreadDomain44();Runnable runnable new Runnable() {public void run() {td.testMethod();}};Thread[] threads new Thread[10];for (int i 0; i 10; i)threads[i] new Thread(runnable);for (int i 0; i 10; i)threads[i].start();Thread.sleep(2000);System.out.println(有 td.lock.getQueueLength() 个线程正在等待);} 看一下运行结果 ThreadName Thread-0进入方法 是否公平锁false 有9个线程正在等待 ReentrantLock默认的是非公平锁因此是否公平锁打印的是false。启动了10个线程只有1个线程lock()了其余9个等待都符合预期。 hasQueuedThread()和hasQueuedThreads()
hasQueuedThread(Thread thread)用来查询指定的线程是否正在等待获取指定的对象监视器
hasQueuedThreads()用于查询是否有线程正在等待获取指定的对象监视器
看一下例子换一个写法ReentrantLock既然是一个类就有类的特性所以这次用继承ReentrantLock的写法这也是很常见的
public class ThreadDomain45 extends ReentrantLock {public void waitMethod() {try {lock();Thread.sleep(Integer.MAX_VALUE);} catch (InterruptedException e) {e.printStackTrace();} finally {unlock();}}}public static void main(String[] args) throws InterruptedException {final ThreadDomain45 td new ThreadDomain45();Runnable runnable new Runnable() {public void run() {td.waitMethod();}};Thread t0 new Thread(runnable);t0.start();Thread.sleep(500);Thread t1 new Thread(runnable);t1.start();Thread.sleep(500);Thread t2 new Thread(runnable);t2.start();Thread.sleep(500);System.out.println(t0 is waiting td.hasQueuedThread(t0));System.out.println(t1 is waiting td.hasQueuedThread(t1));System.out.println(t2 is waiting td.hasQueuedThread(t2));System.out.println(is any thread waiting td.hasQueuedThreads());} 这里加了几个Thread.sleep(500)保证线程按顺序启动其实不按顺序启动也关系不大看一下运行结果 t0 is waitingfalse t1 is waitingtrue t2 is waitingtrue is any thread waitingtrue 由于t0先启动获得了锁因此不等待返回false另外两个线程则要等待获取t0的锁因此返回的是true而此ReentrantLock中有线程在等待所以hasQueuedThreads()返回的是true isHeldByCurrentThread()和isLocked()
isHeldByCurrentThread()表示此对象监视器是否由当前线程保持
isLocked()表示此对象监视器是否由任意线程保持
看一下例子
public class ThreadDomain46 extends ReentrantLock {public void testMethod() {try {lock();System.out.println(Thread.currentThread().getName() 线程持有了锁);System.out.println(Thread.currentThread().getName() 线程是否持有锁 isHeldByCurrentThread());System.out.println(是否任意线程持有了锁 isLocked());Thread.sleep(Integer.MAX_VALUE);} catch (InterruptedException e) {e.printStackTrace();} finally {unlock();}}public void testHoldLock() {System.out.println(Thread.currentThread().getName() 线程是否持有锁 isHeldByCurrentThread());System.out.println(是否任意线程持有了锁 isLocked());}}public static void main(String[] args) {final ThreadDomain46 td new ThreadDomain46();Runnable runnable0 new Runnable() {public void run() {td.testMethod();}};Runnable runnable1 new Runnable() {public void run() {td.testHoldLock();}};Thread t0 new Thread(runnable0);Thread t1 new Thread(runnable1);t0.start();t1.start();} 看一下运行结果 Thread-0线程持有了锁 Thread-1线程是否持有锁false Thread-0线程是否持有锁true 是否任意线程持有了锁true 是否任意线程持有了锁true 这个应该很好理解当前持有锁的是Thread-0线程所以对于Thread-1来说自然不持有锁。 tryLock()和tryLock(long timeout, TimeUnit unit)
tryLock()方法的作用是在调用try()方法的时候如果锁没有被另外一个线程持有那么就返回true否则返回false
tryLock(long timeout, TimeUnit unit)是tryLock()另一个重要的重载方法表示如果在指定等待时间内获得了锁则返回true否则返回false
注意一下tryLock()只探测锁是否并没有lock()的功能要获取锁还得调用lock()方法看一下tryLock()的例子 public class ThreadDomain47 extends ReentrantLock {public void waitMethod() {if (tryLock())System.out.println(Thread.currentThread().getName() 获得了锁);elseSystem.out.println(Thread.currentThread().getName() 没有获得锁);}}public static void main(String[] args) {final ThreadDomain47 td new ThreadDomain47();Runnable runnable new Runnable() {public void run() {td.waitMethod();}};Thread t0 new Thread(runnable);Thread t1 new Thread(runnable);t0.start();t1.start();} 看一下运行结果 Thread-0获得了锁 Thread-1没有获得锁 第一个线程获得了锁返回true第二个线程自然返回的false。由于有了tryLock()这种机制如果一个线程长时间在synchronzied代码/synchronized代码块之中别的线程不得不长时间无限等待的情况将可以被避免。 ReentrantLock中的其他方法
篇幅原因ReentrantLock中还有很多没有被列举到的方法就不写了看一下它们的作用
1、getWaitQueueLength(Condition condition)
类似getQueueLength()不过此方法的前提是condition。比如5个线程每个线程都执行了同一个await()的await()方法那么方法调用的返回值是5因为5个线程都在等待获得锁
2、hasWaiters(Condition condition)
查询是否有线程正在等待与此锁有关的condition条件。比如5个线程每个线程都执行了同一个condition的await()方法那么方法调用的返回值是true因为它们都在等待condition
3、lockInterruptibly()
如果当前线程未被中断则获取锁
4、getWaitingThreads(Condition condition)
返回一个collection它包含可能正在等待与此锁相关给定条件的那些线程因为构造结果的时候实际线程可能动态变化因此返回的collection只是尽力的估计值