首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >等待设置对象的ReadWriteLock

等待设置对象的ReadWriteLock
EN

Stack Overflow用户
提问于 2013-02-04 13:40:21
回答 2查看 629关注 0票数 2

DependingService依赖于异步和动态注入到DependingService.setService(Object)service对象。如果在设置DependingService.doSomething()对象之前调用了service,那么线程应该等待5秒才能使用service

如何进行正确有效的锁定?我的第一个方法是这样的:

代码语言:javascript
复制
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class DependingService {

    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
    private final Condition condition = rwLock.writeLock().newCondition();
    private Object service;


    // service injected dynamically by container
    public void setService(final Object service) {
        rwLock.writeLock().lock();
        try {
            this.service = service;
            System.out.println("Signalling");
            condition.signalAll();
        } finally {
            rwLock.writeLock().unlock();
        }
    }


    public void doSomething() {
        rwLock.readLock().lock();
        try {
            if (service == null) {
                // we can't upgrade to write lock, so release read lock first
                rwLock.readLock().unlock();
                rwLock.writeLock().lock();
                try {
                    if (service == null) {
                        System.out.println("Waiting fo 5 seconds");
                        condition.await(5, TimeUnit.SECONDS);
                    }
                } catch (final InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // downgrade to read lock
                    rwLock.readLock().lock();
                    rwLock.writeLock().unlock();
                }
                if (service == null) {
                    throw new RuntimeException("service is null");
                }
            }

            // use the service
            System.out.println(service.toString());
        } finally {
            rwLock.readLock().unlock();
        }
    }

}

编辑:注意到DependingService.setService(Object)可以随时多次设置为null或任何其他对象。

EN

回答 2

Stack Overflow用户

发布于 2013-02-04 14:45:29

我想不出用高级API构建这种行为的简单方法。请参见下面使用等待/通知模式的建议。要点:

  • servicevolatile,以确保可见性,而不必锁定读取。
  • service总是在doSomething中本地复制,以防止出现这样的情况:您检查服务不为null,然后调用service.toString()并获得NPE,因为在此期间setService(null);已经被调用。
  • 等待时间将在每个while循环中进行调整,以确保等待时间不超过5秒。
  • 它使用基本的同步,但只有当服务为空时--在服务不为空的基本情况下,doSomething中没有争用。如果您每毫秒多次调用setService,您可能会面临性能问题。

注:未测试。

代码语言:javascript
复制
public class DependingService {

    private final Object lock = new Object();
    private volatile Object service;

    // service injected dynamically by container
    public void setService(final Object service) {
        this.service = service;
        synchronized(lock) {
            lock.notifyAll();
        }
    }

    public void doSomething() throws InterruptedException {
        //make a local copy to avoid problems due to service becoming
        //null in the middle of the method
        Object localService = service; 
        if (localService == null ) {
            long end = System.nanoTime() + TimeUnit.NANOSECONDS.convert(5, TimeUnit.SECONDS);
            synchronized(lock) {
                while ((localService = service) == null) {
                    long waitNanos = end - System.nanoTime();
                    if (waitNanos < 0) break;
                    lock.wait(waitNanos / 1000000);
                }
            }
        }
        if (localService == null) {
            throw new RuntimeException("timeout: service is still null");
        }
        // use the service
        System.out.println(localService.toString());
    }
}
票数 2
EN

Stack Overflow用户

发布于 2013-02-04 13:45:00

也许最好像这样使用CountDownLatch:

代码语言:javascript
复制
public class DependingService {
    private final CountDownLatch serviceLatch = new CountDownLatch (1);
    private Object service;

    public void setService (final Object service) 
    {
        this.service = service;
        serviceLatch.countDown ();
    }

    public void doSomething () throws InterruptedException
    {
        if (!serviceLatch.await (5, TimeUnit.SECONDS))
            throw new RuntimeException ("Service is still null");

        // Service is not null here
        System.out.println (service);
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14687983

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档