- 浏览: 746576 次
- 性别:
- 来自: 北京
-
文章分类
最新评论
-
nmgrd:
赞一个,在分析AQS源码的博客当中,楼主是写的最细致,最易懂, ...
java并发编程--AbstractQueuedSynchronizer公平锁和非公平锁分析(三) -
ljzxloaf:
阻塞和等待不一样吧,condition持有等待队列,而AQS持 ...
java并发编程--AbstractQueuedSynchronizer加锁和解锁分析(二) -
DaCang4535:
楼主,不知道你那个book类有什么作用。setBook那个方法 ...
JAXB--简单应用(一) -
yuhui0531:
f-u-c-k!!!!!!!!!!!!!!!!!!!!!!!! ...
java线程常见的几种死锁模式和解决方法 -
刘文超:
form提交的几种方法
java并发编程--AbstractQueuedSynchronizer的lock()和lockInterruptibly()方法分析(五)
- 博客分类:
- Java高级
lock 与 lockInterruptibly比较区别在于:
lock 优先考虑获取锁,待获取锁成功后,才响应中断。
lockInterruptibly 优先考虑响应中断,而不是响应锁的普通获取或重入获取。
详细区别:
ReentrantLock.lockInterruptibly允许在等待时由其它线程调用等待线程的Thread.interrupt方法来中断等待线程的等待而直接返回,这时不用获取锁,而会抛出一个InterruptedException。 ReentrantLock.lock方法不允许Thread.interrupt中断,即使检测到Thread.isInterrupted,一样会继续尝试获取锁,失败则继续休眠。只是在最后获取锁成功后再把当前线程置为interrupted状态,然后再中断线程。
那lockInterruptibly是如何做到这一点的?
public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); }
这里调用了AbstractQueuedSynchronizer.acquireInterruptibly方法。如果线程已被中断则直接抛出异常,否则则尝试获取锁,失败则doAcquireInterruptibly()
AbstractQueuedSynchronizer.acquireInterruptibly(int arg)
/** * Acquires in exclusive mode, aborting if interrupted. * Implemented by first checking interrupt status, then invoking * at least once {@link #tryAcquire}, returning on * success. Otherwise the thread is queued, possibly repeatedly * blocking and unblocking, invoking {@link #tryAcquire} * until success or the thread is interrupted. This method can be * used to implement method {@link Lock#lockInterruptibly}. * * @param arg the acquire argument. This value is conveyed to * {@link #tryAcquire} but is otherwise uninterpreted and * can represent anything you like. * @throws InterruptedException if the current thread is interrupted */ public final void acquireInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (!tryAcquire(arg)) doAcquireInterruptibly(arg); }
AbstractQueuedSynchronizer.doAcquireInterruptibly大体上相当于前面的acquireQueued,关键的区别在于检测到interrupted后的处理,acquireQueued简单的记录下中断曾经发生,然后就象没事人似的去尝试获取锁,失败则休眠。而doAcquireInterruptibly检测到中断则直接退出循环,抛出InterruptedException异常。
AbstractQueuedSynchronizer.doAcquireInterruptibly(int arg)
/** * Acquires in exclusive interruptible mode. * @param arg the acquire argument */ private void doAcquireInterruptibly(int arg) throws InterruptedException { final Node node = addWaiter(Node.EXCLUSIVE); try { for (;;) { final Node p = node.predecessor(); /* acquireQueued代码: if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; */ if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC return; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) break; } } catch (RuntimeException ex) { cancelAcquire(node); throw ex; } // Arrive here only if interrupted // 取消获取锁尝试,将当前节点从等待队列中移除 cancelAcquire(node); throw new InterruptedException(); }
在抛出异常之前,doAcquireInterruptibly还做了一件事情,cancelAcquire。cancelAcquire中有些细节值得玩味,参见代码中笔者注释。
AbstractQueuedSynchronizer.cancelAcquire(Node node)
/** * Cancels an ongoing attempt to acquire. * * @param node the node */ private void cancelAcquire(Node node) { // Ignore if node doesn"t exist if (node == null) return; node.thread = null; // Skip cancelled predecessors // 头节点一定不会是在等待状态,所以不会被cancel,所以这里一定能找到一个节点而不用担心null Node pred = node.prev; while (pred.waitStatus > 0) node.prev = pred = pred.prev; // Getting this before setting waitStatus ensures staleness Node predNext = pred.next; // Can use unconditional write instead of CAS here node.waitStatus = Node.CANCELLED; // If we are the tail, remove ourselves if (node == tail && compareAndSetTail(node, pred)) { compareAndSetNext(pred, predNext, null); } else { // If "active" predecessor found... if (pred != head && (pred.waitStatus == Node.SIGNAL || compareAndSetWaitStatus( pred, 0, Node.SIGNAL)) && pred.thread != null) { // If successor is active, set predecessor"s next link Node next = node.next; if (next != null && next.waitStatus <= 0) compareAndSetNext(pred, predNext, next); } else { /*这里如果不调用unparkSuccessor, 若在interrupted之后,执行到上面一句将waitStatus置CANCELLED之前,锁被释放,该线程被唤醒,则释放锁线程的unparkSuccessor不能起到预期作用,所以这里需要调用unparkSuccessor.即使此时持有锁的线程没有释放锁也不会有严重后果,被unpark的线程在获取锁失败后会继续park*/ unparkSuccessor(node); } node.next = node; // help GC } }
发表评论
-
thread方法分析
2012-02-02 13:36 0t.join();表示当前线程停止执行直到t线程运行完毕 ... -
线程池--jetty中QueuedThreadPool分析(一)
2012-02-02 11:09 15741jetty版本:jetty-6.1.26 1.由于jetty ... -
线程池--jetty中QueuedThreadPool分析(一)
2012-02-02 10:48 0d -
java并发编程--ThreadLocal的用法和分析
2012-01-11 22:55 17742ThreadLocal这个类,理解起来比较简单,但是使用时, ... -
java并发编程--Semaphore信号量分析(七)
2012-01-08 22:25 0Mutex是一把钥匙,一个人拿了就可进入一个房间,出来的时候把 ... -
java并发编程--AbstractQueuedSynchronizer的tryLock()方法分析(六)
2012-01-05 14:40 2382tryLock()仅尝试一次获取锁,不管成功与否,都将返回结 ... -
java并发编程--AbstractQueuedSynchronizer条件锁分析(四)
2011-12-30 17:10 2327前一篇J.U.C的 ... -
java并发编程--AbstractQueuedSynchronizer公平锁和非公平锁分析(三)
2011-12-30 14:40 3979juc包中,aqs实现的公平锁和非公平锁的最主要的区别是:非 ... -
java并发编程--AbstractQueuedSynchronizer加锁和解锁分析(二)
2011-12-29 22:07 8662在java.util.concurrent.locks ... -
JAXB--@XmlType注解标注xml生成顺序(四)
2011-11-03 17:01 34485默认情况下,Jaxb编组出来的xml中的字段顺序是随机的,你可 ... -
JAXB--@XmlElementWrapper注解和泛型一起使用(三)
2011-11-03 16:46 20815当java对象的某个属性使 ... -
JAXB--@XmlElementWrapper注解(二)
2011-11-03 15:49 32563在JAXB标准中,@XmlElementWrapper注解表示 ... -
JAXB--简单应用(一)
2011-11-03 15:09 50531一、简介 1、概念是什么:(Java Archite ... -
Java线程:新特征-锁
2011-10-28 17:39 0在Java5中,专门提供了锁对象,利用锁可以方便的实现资源的 ... -
java线程常见的几种死锁模式和解决方法
2011-10-18 23:09 2271待续 -
利用object.wait()和实现生产者和消费者模式
2011-10-18 23:08 2627其实生产者和消费者模式概念很简单,就是生产者将生产出来 ... -
java线程的同步互斥和通讯
2011-10-18 23:01 3680一、同步和锁定 1、锁的原理 Ja ... -
HtmlParser学习笔记(四)-- 使用Filter过滤结点
2010-01-12 12:48 11310使用TagNameFilter过滤所有table标签结 ... -
HtmlParser学习笔记(三)-- 使用Visitor访问结点
2010-01-12 12:48 5459使用NodeVisitor方式访问html结点,代码如 ... -
HtmlParser学习笔记(二)-- 遍历结点
2010-01-12 12:47 4391这次主要演示下,如何迭代一个Node结点的所有根子结点。 ...
相关推荐
"04 并发编程专题07.zip"这个压缩包文件包含的两个子文件" Synchronized&Lock&AQS详解(上)(1).vep"和"Synchronized&Lock&AQS详解(上)(2).vep"很显然是关于Java并发编程中的关键概念——同步机制的深入讲解。...
在Java并发编程中,显式锁(Lock)和隐式锁(synchronized)是两种常见的锁机制,它们提供了对共享资源的互斥访问。显式锁通过Java的Lock接口实现,而隐式锁主要依赖于synchronized关键字。 **Lock接口和...
在Java并发编程中,AbstractQueuedSynchronizer(AQS)是一个核心的同步组件,用于构建锁和同步器的基础框架。AQS是一个抽象类,它提供了线程同步的基本机制,包括线程的排队、等待和唤醒。在Java.util.concurrent...
Lock 接口中的方法有 lock()、lockInterruptibly()、tryLock()、tryLock(long time, TimeUnit unit)和 unlock()。 * lock():获取锁,拿不到锁会阻塞,等待其他线程释放锁,获取到锁后返回。 * lockInterruptibly()...
ReentrantLock及JUC其他并发工具类为Java多线程编程提供了强大的支持,大大简化了并发程序的开发难度,提高了并发控制的灵活性和性能。熟练掌握这些工具对于编写高效、稳定、安全的多线程应用至关重要。