当前位置: 首页 > news >正文

企业微网站建站wordpress带下载功能

企业微网站建站,wordpress带下载功能,wordpress 文字 居中,做pc端网站如何一、简介在Java中通常实现锁有两种方式#xff0c;一种是synchronized关键字#xff0c;另一种是Lock。二者其实并没有什么必然联系#xff0c;但是各有各的特点#xff0c;在使用中可以进行取舍的使用。二、ReentrantLock与synchronized的比较相同点#xff1a; #xf…一、简介在Java中通常实现锁有两种方式一种是synchronized关键字另一种是Lock。二者其实并没有什么必然联系但是各有各的特点在使用中可以进行取舍的使用。二、ReentrantLock与synchronized的比较相同点 1ReentrantLock提供了synchronized类似的功能和内存语义。不同点1ReentrantLock功能性方面更全面比如定时等候锁、可中断锁等候、锁投票等因此更有扩展性。在多个条件变量和高度竞争锁的地方用ReentrantLock更合适ReentrantLock还提供了Condition对线程的等待和唤醒等操作更加灵活一个ReentrantLock可以有多个Condition实例所以更有扩展性。2ReentrantLock 的性能比synchronized会好点。3ReentrantLock提供了可轮询的锁请求他可以尝试的去取得锁如果取得成功则继续处理取得不成功可以等下次运行的时候处理所以不容易产生死锁而synchronized则一旦进入锁请求要么成功要么一直阻塞所以更容易产生死锁。4对于使用者的直观体验上Lock是比较复杂的需要lock和realse通常需要在finally中进行锁的释放否则如果受保护的代码将抛出异常就会产生死锁的问题这一点区别看起来可能没什么但是实际上它极为重要。但是synchronized的使用十分简单只需要对自己的方法或者关注的同步对象或类使用synchronized关键字即可JVM 将确保锁会获得自动释放。但是对于锁的粒度控制比较粗同时对于实现一些锁的状态的转移比较困难。5 当 JVM 用 synchronized 管理锁定请求和释放时JVM 在生成线程转储时能够包括锁定信息。这些对调试非常有价值因为它们能标识死锁或者其他异常行为的来源。 Lock 类只是普通的类JVM 不知道具体哪个线程拥有 Lock 对象。三、ReentrantLockjava.util.concurrent.lock 中的 Lock 框架是锁定的一个抽象它允许把锁定的实现作为 Java 类而不是作为语言的特性来实现。这就为 Lock 的多种实现留下了空间各种实现可能有不同的调度算法、性能特性或者锁定语义。 ReentrantLock 类实现了 Lock 它拥有与 synchronized 相同的并发性和内存语义但是添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外它还提供了在激烈争用情况下更佳的性能。换句话说当许多线程都想访问共享资源时JVM 可以花更少的时候来调度线程把更多时间用在执行线程上。reentrant 锁意味着什么呢简单来说它有一个与锁相关的获取计数器如果拥有锁的某个线程再次得到锁那么获取计数器就加1然后锁需要被释放两次才能获得真正释放。这模仿了 synchronized 的语义如果线程进入由线程已经拥有的监控器保护的 synchronized 块就允许线程继续进行当线程退出第二个或者后续 synchronized 块的时候不释放锁只有线程退出它进入的监控器保护的第一个 synchronized 块时才释放锁。1、实现可轮询的锁请求在内部锁中死锁是致命的——唯一的恢复方法是重新启动程序唯一的预防方法是在构建程序时不要出错。而可轮询的锁获取模式具有更完善的错误恢复机制可以规避死锁的发生。        如果你不能获得所有需要的锁那么使用可轮询的获取方式使你能够重新拿到控制权它会释放你已经获得的这些锁然后再重新尝试。可轮询的锁获取模式由tryLock()方法实现。此方法仅在调用时锁为空闲状态才获取该锁。如果锁可用则获取锁并立即返回值true。如果锁不可用则此方法将立即返回值false。此方法的典型使用语句如下 Lock lock ...; if (lock.tryLock()) { try { // manipulate protected state } finally { lock.unlock(); } } else { // perform alternative actions } 2、实现可定时的锁请求当使用内部锁时一旦开始请求锁就不能停止了所以内部锁给实现具有时限的活动带来了风险。为了解决这一问题可以使用定时锁。当具有时限的活 动调用了阻塞方法定时锁能够在时间预算内设定相应的超时。如果活动在期待的时间内没能获得结果定时锁能使程序提前返回。可定时的锁获取模式由tryLock(long, TimeUnit)方法实现。 3、实现可中断的锁获取请求        可中断的锁获取操作允许在可取消的活动中使用。lockInterruptibly()方法能够使你获得锁的时候响应中断。四、条件变量Condition条件变量很大一个程度上是为了解决Object.wait/notify/notifyAll难以使用的问题。条件也称为条件队列 或条件变量为线程提供了一个含义以便在某个状态条件现在可能为 true 的另一个线程通知它之前一直挂起该线程即让其“等待”。因为访问此共享状态信息发生在不同的线程中所以它必须受保护因此要将某种形式的锁与该条件相关联。等待提供一个条件的主要属性是以原子方式 释放相关的锁并挂起当前线程就像 Object.wait 做的那样。       上述API说明表明条件变量需要与锁绑定而且多个Condition需要绑定到同一锁上。前面的Lock中提到获取一个条件变量的方法是Lock.newCondition()。void await() throws InterruptedException; void awaitUninterruptibly(); long awaitNanos(long nanosTimeout) throws InterruptedException; boolean await(long time, TimeUnit unit) throws InterruptedException; boolean awaitUntil(Date deadline) throws InterruptedException; void signal(); void signalAll();        以上是Condition接口定义的方法await*对应于Object.waitsignal对应于Object.notifysignalAll对应于Object.notifyAll。特别说明的是Condition的接口改变名称就是为了避免与Object中的wait/notify/notifyAll的语义和使用上混淆因为Condition同样有wait/notify/notifyAll方法。       每一个Lock可以有任意数据的Condition对象Condition是与Lock绑定的所以就有Lock的公平性特性如果是公平锁线程为按照FIFO的顺序从Condition.await中释放如果是非公平锁那么后续的锁竞争就不保证FIFO顺序了。一个使用Condition实现生产者消费者的模型例子如下。import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ProductQueueT { private final T[] items; private final Lock lock new ReentrantLock(); private Condition notFull lock.newCondition(); private Condition notEmpty lock.newCondition(); // private int head, tail, count; public ProductQueue(int maxSize) { items (T[]) new Object[maxSize]; } public ProductQueue() { this(10); } public void put(T t) throws InterruptedException { lock.lock(); try { while (count getCapacity()) { notFull.await(); } items[tail] t; if (tail getCapacity()) { tail 0; } count; notEmpty.signalAll(); } finally { lock.unlock(); } } public T take() throws InterruptedException { lock.lock(); try { while (count 0) { notEmpty.await(); } T ret items[head]; items[head] null;//GC // if (head getCapacity()) { head 0; } --count; notFull.signalAll(); return ret; } finally { lock.unlock(); } } public int getCapacity() { return items.length; } public int size() { lock.lock(); try { return count; } finally { lock.unlock(); } } }        在这个例子中消费take()需要 队列不为空如果为空就挂起await()直到收到notEmpty的信号生产put()需要队列不满如果满了就挂起await()直到收到notFull的信号。       可能有人会问题如果一个线程lock()对象后被挂起还没有unlock那么另外一个线程就拿不到锁了lock()操作会挂起那么就无法通知(notify)前一个线程这样岂不是“死锁”了1、await* 操作上一节中说过多次ReentrantLock是独占锁一个线程拿到锁后如果不释放那么另外一个线程肯定是拿不到锁所以在lock.lock()和lock.unlock()之间可能有一次释放锁的操作同样也必然还有一次获取锁的操作。我们再回头看代码不管take()还是put()在进入lock.lock()后唯一可能释放锁的操作就是await()了。也就是说await()操作实际上就是释放锁然后挂起线程一旦条件满足就被唤醒再次获取锁public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node addConditionWaiter(); int savedState fullyRelease(node); int interruptMode 0; while (!isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode checkInterruptWhileWaiting(node)) ! 0) break; } if (acquireQueued(node, savedState) interruptMode ! THROW_IE) interruptMode REINTERRUPT; if (node.nextWaiter ! null) unlinkCancelledWaiters(); if (interruptMode ! 0) reportInterruptAfterWait(interruptMode); } 上面是await()的代码片段。上一节中说过,AQS在获取锁的时候需要有一个CHL的FIFO队列所以对于一个Condition.await()而言如果释放了锁要想再一次获取锁那么就需要进入队列等待被通知获取锁。完整的await()操作是安装如下步骤进行的将当前线程加入Condition锁队列。特别说明的是这里不同于AQS的队列这里进入的是Condition的FIFO队列。后面会具体谈到此结构。进行2。释放锁。这里可以看到将锁释放了否则别的线程就无法拿到锁而发生死锁。进行3。自旋(while)挂起直到被唤醒或者超时或者CACELLED等。进行4。获取锁(acquireQueued)。并将自己从Condition的FIFO队列中释放表明自己不再需要锁我已经拿到锁了。这里再回头介绍Condition的数据结构。我们知道一个Condition可以在多个地方被await*()那么就需要一个FIFO的结构将这些Condition串联起来然后根据需要唤醒一个或者多个通常是所有。所以在Condition内部就需要一个FIFO的队列。 private transient Node firstWaiter; private transient Node lastWaiter; 上面的两个节点就是描述一个FIFO的队列。我们再结合前面提到的节点Node数据结构。我们就发现Node.nextWaiter就派上用场了nextWaiter就是将一系列的Condition.await*串联起来组成一个FIFO的队列。2、signal/signalAll 操作await*()清楚了现在再来看signal/signalAll就容易多了。按照signal/signalAll的需求就是要将Condition.await*()中FIFO队列中第一个Node唤醒或者全部Node唤醒。尽管所有Node可能都被唤醒但是要知道的是仍然只有一个线程能够拿到锁其它没有拿到锁的线程仍然需要自旋等待就上上面提到的第4步(acquireQueued)。 private void doSignal(Node first) { do { if ( (firstWaiter first.nextWaiter) null) lastWaiter null; first.nextWaiter null; } while (!transferForSignal(first) (first firstWaiter) ! null); } private void doSignalAll(Node first) { lastWaiter firstWaiter null; do { Node next first.nextWaiter; first.nextWaiter null; transferForSignal(first); first next; } while (first ! null); } 上面的代码很容易看出来signal就是唤醒Condition队列中的第一个非CANCELLED节点线程而signalAll就是唤醒所有非CANCELLED节点线程。当然了遇到CANCELLED线程就需要将其从FIFO队列中剔除。final boolean transferForSignal(Node node) { if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; Node p enq(node); int c p.waitStatus; if (c 0 || !compareAndSetWaitStatus(p, c, Node.SIGNAL)) LockSupport.unpark(node.thread); return true; } 上面就是唤醒一个 await*() 线程的过程根据前面的小节介绍的如果要 unpark 线程并使线程拿到锁那么就需要线程节点进入 AQS 的队列。所以可以看到在 LockSupport.unpark 之前调用了 enq(node) 操作将当前节点加入到 AQS 队列。
http://www.zqtcl.cn/news/61979/

相关文章:

  • 苏州h5网站建设价格wordpress弹出框插件
  • 湖南省住房与城乡建设厅网站官网百科网站模板
  • 公司网站建设需要多少钱导购网站制作
  • 阳江市做网站网站开发 建设叫什么
  • 网站建设的公司上海泉州做网站的企业
  • 一定火网站建设定制网站页面优化签象客
  • 做爰网站視屏500万在北京几环买房
  • 广播电视网站建设网站开发微信端
  • 农业网站源码带数据凡客诚品为什么不火了
  • 网站建设公司的专业度该怎么去看电影html网页模板设计素材
  • 怎么可以找到做公益的网站关于卖零食网站建设需求分析
  • 如何给网站做外链湖南seo推广
  • 网站树状型结构优化wordpress编码查看
  • 快捷的网站建设软件网站主要盈利模式
  • 塘坑网站建设服装网站网络建设和硬件资源
  • 大连旅顺网站制作app官网入口
  • 网站建设营业执照营销网站找什么公司做
  • 吉林网站建设业务浙江省网站集约化建设通知
  • 如何设计网站的链接肯德基网站建设
  • 克拉玛依建设局网站网站建设多少钱宋柯
  • 网站建设上海公司线上推广方式有哪些
  • 学做文案的网站seo网站推广
  • 怎么查询网站备案信息查询如何开发电子商务网站
  • php源码网站建设教程江门市华企立方科技有限公司
  • 移动商城网站建设怎样宣传自己的品牌
  • 代做毕业设计网站做美剧网站侵权
  • 用python做音乐网站免费空间+网站空间+虚拟主机
  • 网站空间绑定域名全媒体广告策划营销
  • 自助服务系统网站南通网站制作推广
  • 网站建设教程 企业邮箱电商网站设计哪家好