Java 中的锁入门介绍

发布时间:2017-2-27 23:52:28 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"Java 中的锁入门介绍",主要涉及到Java 中的锁入门介绍方面的内容,对于Java 中的锁入门介绍感兴趣的同学可以参考一下。

本章是简单介绍java世界中的锁,从介绍一个简单的锁开始, 让大家明白什么是锁,再介绍可重入锁,字面上难以理解,其实内容很简单。 最后说一说何谓公平锁,和一点锁使用中的注意事项。大都是通过简单的代码 让大家能理解,用代码解释是最容易理解的了。 一、一个简单的锁 publicclassCounter{ privateintcount = 0; publicintinc(){ synchronized(this){ return++count; } } }   够简单吧,是用传统的同步关键字实现。如果用Lock关键字实现则是这个样子 publicclassSimpleLock { privatebooleanisLocked = false; publicsynchronizedvoid lock() throwsInterruptedException { while(isLocked) { System.out.println("锁已被获取,等待中..."); wait(); } isLocked = true; } publicsynchronizedvoid unlock() { isLocked = false; notify(); } } publicclassCounter{ privateLock lock = newLock(); privateintcount = 0; publicintinc(){ lock.lock(); intnewCount = ++count; lock.unlock(); returnnewCount; } } 二、可重入锁 其实意思就是假如有两个方法,你持有了其中的一个锁,而令一个方法也是用的这个锁,那么你可以进入第二个方法,代码 publicclassReentrant { publicsynchronizedvoid outer() { inner(); } publicsynchronizedvoid inner() { System.out.println("==========="); } publicstaticvoid main(String[] args) { Reentrant rt = newReentrant(); rt.outer(); } } 这个时候你调用 outer方法,你得到了这个对象的锁,你在outer() 方法中是可以执行inner方法的,为什么?因为inner方法的锁就是这个对象,而你已经获得了。让我们来修改一下上面的 SimpleLock 类,把他变成一下可重入的锁吧 publicclassReentrantLock { booleanisLocked = false; Thread lockedBy = null; intlockedCount = 0; publicsynchronizedvoid lock() throwsInterruptedException { Thread callingThread = Thread.currentThread(); while(isLocked && lockedBy != callingThread) { wait(); } isLocked = true; lockedCount++; lockedBy = callingThread; } publicsynchronizedvoid unlock() { if(Thread.currentThread() == this.lockedBy) { lockedCount--; if(lockedCount == 0) { isLocked = false; notify(); } } } } 类很简单,不需要多说 ,就是判断了一下获取当前锁的对象是不是当前锁的持有人,如果是,就依然能执行lock() 方法后的代码块。以上的2个锁方法的却别可以自己通过如下测试方法运行的看看 publicclassTestMain { SimpleLock lock = newSimpleLock(); publicvoidouter() throwsInterruptedException { lock.lock(); inner(); lock.unlock(); } publicsynchronizedvoid inner() throwsInterruptedException { lock.lock(); System.out.println("==================="); lock.unlock(); } publicstaticvoid main(String[] args) throwsInterruptedException { TestMain rt = newTestMain(); rt.outer(); } } 使用简单锁,outer方法中调用inner方法会wait ,看看 SimpleLock 的代码就知道为什么了,因为每次调用时都会先调用 lock() 方法而此时lock方法已经被调用过,并还没有unlock()。 三、公平锁 概念就不解释了。java中的synchronized关键字不能保证线程执行的公平性,相对来说使用 Lock来做同步会比用 同步关键字更公平一点。我们先来看一段代码 publicclassSynchronizer{ publicsynchronizedvoid doSynchronized(){ //do a lot of work which takes a long time } } 假设有A B C 3个线程调用该方法,当前在执行的是A线程,其他的会等待,此时A线程执行完后,B先抢占了,B开始执行,这时A又要执行该方法,有一种可能情况是A B线程的优先级或其他原因,导致C线程一直得不到执行机会。下面的方法会相对公平些: publicclassSynchronizer{ Lock lock = newLock(); publicvoiddoSynchronized() throwsInterruptedException{ this.lock.lock(); //critical section, do a lot of work which takes a long time this.lock.unlock(); } } publicclassLock{ privatebooleanisLocked = false; privateThread lockingThread = null; publicsynchronizedvoid lock() throwsInterruptedException{ while(isLocked){ wait(); } isLocked = true; lockingThread = Thread.currentThread(); } publicsynchronizedvoid unlock(){ if(this.lockingThread != Thread.currentThread()){ thrownewIllegalMonitorStateException( "Calling thread has not locked this lock"); } isLocked = false; lockingThread = null; notify(); } } 为什么比同步关键字更公平,因为同步关键字是线程间的竞争,而Lock对每个线程都是同等对待,他通过notify()来决定接下来执行的是那个线程。也许你觉得这个也不怎么公平,应为你依然不确定线程执行的优先规则,那么下面的例子应该会让你觉得更公平。 importjava.util.ArrayList; importjava.util.List; publicclassFairLock { privatebooleanisLocked = false; privateThread lockingThread = null; privateList<QueueObject> waitingThreads = newArrayList<QueueObject>(); publicvoidlock() throwsInterruptedException { QueueObject queueObject = newQueueObject(); booleanisLockedForThisThread = true; synchronized(this) { waitingThreads.add(queueObject); } while(isLockedForThisThread) { synchronized(this) { isLockedForThisThread = isLocked || waitingThreads.get(0) != queueObject; if(!isLockedForThisThread) { isLocked = true; waitingThreads.remove(queueObject); lockingThread = Thread.currentThread(); return; } } try{ queueObject.doWait(); }catch(InterruptedException e) { synchronized(this) { waitingThreads.remove(queueObject); } throwe; } } } publicsynchronizedvoid unlock() { if(this.lockingThread != Thread.currentThread()) { thrownewIllegalMonitorStateException( "Calling thread has not locked this lock"); } isLocked = false; lockingThread = null; if(waitingThreads.size() > 0) { waitingThreads.get(0).doNotify(); } } } publicclassQueueObject { privatebooleanisNotified = false; publicsynchronizedvoid doWait() throwsInterruptedException { while(!isNotified) { this.wait(); } this.isNotified = false; } publicsynchronizedvoid doNotify() { this.isNotified = true; this.notify(); } publicbooleanequals(Object o) { returnthis== o; } } 代码很简单,大家都看的出来,只是用了一个List来保存所有想执行的线程,这当然会比普通锁效率低,但他能让你知道是通过什么规则来分配执行资源的,这里就是先到先执行,你也可以实现自己更复杂的排序算法。不过想要说明一下的是 java中不太可能能保证绝对的线程公平。 四、别忘了在finally中调用unlock lock.lock(); try{ //do something }finally{ lock.unlock(); }

上一篇:灯火阑珊处等你回眸
下一篇:LeetCode - Binary Tree Postorder Traversal

相关文章

相关评论

本站评论功能暂时取消,后续此功能例行通知。

一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!

二、互相尊重,对自己的言论和行为负责。