站长网 语言 锁的使用至关重要

锁的使用至关重要

副标题#e# 独占锁的实现,拥有上面列举的除读写锁之外的所有特性,使用比较简单 classX{ //创建独占锁实例 privatefinalReentrantLocklock=newReentrantLock(); //… publicvoidm(){ lock.lock();//blockuntilconditionholds try{ //…methodbody }finall

副标题#e#

独占锁的实现,拥有上面列举的除读写锁之外的所有特性,使用比较简单

class X {  

   // 创建独占锁实例  

   private final ReentrantLock lock = new ReentrantLock();  

   // …  

   public void m() {  

     lock.lock();  // block until condition holds  

     try {  

       // … method body  

     } finally {  

       // 必须要释放锁,unlock与lock成对出现  

       lock.unlock()  

     } 

   }  

 } 

ReentrantReadWriteLock

读写锁的实现,拥有上面列举的所有特性。并且写锁可降级为读锁,反之不行。

class CachedData {  

   Object data;  

   volatile boolean cacheValid;  

   final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();  

   void processCachedData() {  

     rwl.readLock().lock();  

     if (!cacheValid) {  

       // Must release read lock before acquiring write lock  

       rwl.readLock().unlock();  

       rwl.writeLock().lock(); 

        try {  

         // Recheck state because another thread might have  

         // acquired write lock and changed state before we did.  

         if (!cacheValid) {  

           data = …  

           cacheValid = true;  

         }  

         // Downgrade by acquiring read lock before releasing write lock  

         rwl.readLock().lock();  

       } finally { 

         rwl.writeLock().unlock(); // Unlock write, still hold read  

       }  

     }  

     try {  

       use(data);  

     } finally {  

       rwl.readLock().unlock();  

     }  

   }  

 } 

StampedLock

StampedLock也是一种读写锁,提供两种读模式:乐观读和悲观读。乐观读允许读的过程中也可以获取写锁后写入!这样一来,我们读的数据就可能不一致,所以,需要一点额外的代码来判断读的过程中是否有写入。

#p#副标题#e#

乐观锁的意思就是乐观地估计读的过程中大概率不会有写入,因此被称为乐观锁。反过来,悲观锁则是读的过程中拒绝有写入,也就是写入必须等待。显然乐观锁的并发效率更高,但一旦有小概率的写入导致读取的数据不一致,需要能检测出来,再读一遍就行。

public class Point {  

    private final StampedLock stampedLock = new StampedLock();  

    private double x;  

    private double y; 

    public void move(double deltaX, double deltaY) {  

        long stamp = stampedLock.writeLock(); // 获取写锁  

        try {  

            x += deltaX;  

            y += deltaY;  

        } finally {  

            stampedLock.unlockWrite(stamp); // 释放写锁  

        }  

    }  

    public double distanceFromOrigin() { 

        long stamp = stampedLock.tryOptimisticRead(); // 获得一个乐观读锁  

        // 注意下面两行代码不是原子操作  

        // 假设x,y = (100,200)  

        double currentX = x;  

        // 此处已读取到x=100,但x,y可能被写线程修改为(300,400)  

        double currentY = y;  

        // 此处已读取到y,如果没有写入,读取是正确的(100,200)  

        // 如果有写入,读取是错误的(100,400)  

        if (!stampedLock.validate(stamp)) { // 检查乐观读锁后是否有其他写锁发生  

            stamp = stampedLock.readLock(); // 获取一个悲观读锁  

            try {  

                currentX = x;  

                currentY = y;  

            } finally {  

                stampedLock.unlockRead(stamp); // 释放悲观读锁 

            }  

        }  

        return Math.sqrt(currentX * currentX + currentY * currentY);  

    }  

Condition#p#副标题#e##p#分页标题#e#

Condition成为条件队列或条件变量,为一个线程挂起执行(等待)提供了一种方法,直到另一线程通知某些状态条件现在可能为真为止。由于对该共享状态信息的访问发生在不同的线程中,因此必须由互斥锁对其其进行保护。

await方法:必须在获取锁之后的调用,表示释放当前锁,阻塞当前线程;等待其他线程调用锁的signal或signalAll方法,线程唤醒重新获取锁。

Lock配合Condition,可以实现synchronized 与 对象(wait,notify)同样的效果,来进行线程间基于共享变量的通信。但优势在于同一个锁可以由多个条件队列,当某个条件满足时,只需要唤醒对应的条件队列即可,避免无效的竞争。

// 此类实现类似阻塞队列(ArrayBlockingQueue)  

class BoundedBuffer {  

 final Lock lock = new ReentrantLock();  

 final Condition notFull  = lock.newCondition();   

 final Condition notEmpty = lock.newCondition();   

 final Object[] items = new Object[100];  

 int putptr, takeptr, count;  

 public void put(Object x) throws InterruptedException {  

   lock.lock();  

   try {  

     while (count == items.length)  

       notFull.await();  

     items[putptr] = x;  

     if (++putptr == items.length) putptr = 0;  

     ++count;  

     notEmpty.signal();  

   } finally {  

     lock.unlock();  

   }  

 }  

 public Object take() throws InterruptedException {  

   lock.lock();  

   try {  

     while (count == 0)  

       notEmpty.await();  

     Object x = items[takeptr];  

     if (++takeptr == items.length) takeptr = 0;  

     –count;  

     notFull.signal();  

     return x;  

   } finally {  

     lock.unlock();  

   }  

 }  

BlockingQueue#p#副标题#e##p#分页标题#e#

BlockingQueue阻塞队列实际上是一个生产者/消费者模型,当队列长度大于指定的最大值,生产线程就会被阻塞;反之当队列元素为空时,消费线程就会被阻塞;同时当消费成功时,就会唤醒阻塞的生产者线程;生产成功就会唤醒消费者线程;

内部使用就是ReentrantLock + Condition来实现的,可以参照上面的示例。

本文来自网络,不代表站长网立场,转载请注明出处:https://www.tzzz.com.cn/html/biancheng/yuyan/2021/0525/6310.html

作者: dawei

【声明】:站长网内容转载自互联网,其相关言论仅代表作者个人观点绝非权威,不代表本站立场。如您发现内容存在版权问题,请提交相关链接至邮箱:bqsm@foxmail.com,我们将及时予以处理。
联系我们

联系我们

0577-28828765

在线咨询: QQ交谈

邮箱: xwei067@foxmail.com

工作时间:周一至周五,9:00-17:30,节假日休息

返回顶部