DependingService依赖于异步和动态注入到DependingService.setService(Object)的service对象。如果在设置DependingService.doSomething()对象之前调用了service,那么线程应该等待5秒才能使用service。
如何进行正确有效的锁定?我的第一个方法是这样的:
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或任何其他对象。
发布于 2013-02-04 14:45:29
我想不出用高级API构建这种行为的简单方法。请参见下面使用等待/通知模式的建议。要点:
service是volatile,以确保可见性,而不必锁定读取。service总是在doSomething中本地复制,以防止出现这样的情况:您检查服务不为null,然后调用service.toString()并获得NPE,因为在此期间setService(null);已经被调用。doSomething中没有争用。如果您每毫秒多次调用setService,您可能会面临性能问题。注:未测试。
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());
}
}发布于 2013-02-04 13:45:00
也许最好像这样使用CountDownLatch:
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);
}
}https://stackoverflow.com/questions/14687983
复制相似问题