我正在尝试设置一个从设备Quantis - Quantum Random Number Generator
提供真随机数的服务器。我使用Grails框架构建了Web应用程序,在Tomcat
上的Ubuntu
服务器上运行。
由于只有一个设备,我必须安排访问它的线程,对吗?所以我在调用此设备的函数(ReadInt, ReadDouble, ReadFloat
)上设置了信号量(带有1个资源)。包含这些函数的对象称为Quantis
,存储在Grails应用程序的Java源包中,它实现为单例;然后控制器将调用该对象及其功能的实例。然后,这些功能中的每一个都将调用系统上的Quantis库以从设备读取流< - 现在这是关键区域。我需要确保此设备一次只能有一个请求。
信号量似乎工作正常。但是如果我刷新页面(检索随机数流)真的很快(比如+/- 10次)就会崩溃。我“盲目地”尝试了许多来自互联网的方法,包括grails executors
,但似乎没有任何工作(但我可能没有正确实现它们,真的)。
有没有人知道如何解决这个问题?
这是我的一个函数的代码:(它们看起来都是相同的样式,但在检索数据时调用不同的系统库函数)
private static final Semaphore ticket = new Semaphore(1, true); ... public int ReadInt(int min, int max) throws QuantisException { while (true) { try { ticket.acquire(); int data = QuantisReadScaledInt(deviceType.getType(), deviceNumber, min, max); ticket.release(); return data; } catch (InterruptedException ex) { } catch (QuantisException ex) { ticket.release(); throw ex; } } }
答案 0 :(得分:1)
首先,“它会崩溃”对所发生的事情描述不佳。有异常吗?究竟发生了什么?
其次,您确定需要同步对API的访问。如果它提供了Java API,那么这个API很可能已经同步,并且不需要你的信号量。
第三,如果你获得了一个信号量,你应该在finally块中释放它。无论在try块中发生什么,这都可以保证它被释放:
ticket.acquire();
try {
...
}
catch (...)
finally {
ticket.release();
}
第四:我不明白while(true)
循环的要点。它循环的唯一时间是InterruptedException。并且InterruptedException正好用于表示线程应该停止执行ASAP。所以你的方法应该抛出这个异常,而不是吞下它。
最后,您应该学习Java命名约定并坚持使用它们。方法以小写字母开头。
如果你真的需要同步访问,那么我将重写方法:
public int readInt(int min, int max) throws QuantisException, InterruptedException {
ticket.acquire();
try {
return quantisReadScaledInt(deviceType.getType(), deviceNumber, min, max);
}
finally {
ticket.release();
}
}
如果要确保只有一个线程可以访问本机库函数,请使用以下类:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class SingleThreadAccess {
public static final SingleThreadAccess INSTANCE = new SingleThreadAccess();
private ExecutorService executor;
// to be called by ServletContextListener.contextInitialized()
public void init() {
executor = Executors.newSingleThreadExecutor();
}
// to be called by ServletContextListener.contextDestroyed()
public void shutdown() {
executor.shutdown();
try {
executor.awaitTermination(2L,TimeUnit.SECONDS);
}
catch (InterruptedException e) {
}
executor.shutdownNow();
}
public int readInt(int min, int max) throws QuantisException, InterruptedException {
Callable<Integer> task = new Callable<Integer>() {
@Override
public Integer call() throws QuantisException {
return quantisReadScaledInt(deviceType.getType(), deviceNumber, min, max);
}
};
Future<Integer> future = executor.submit(task);
try {
future.get();
}
catch (ExecutionException e) {
unwrap(e);
}
}
private void unwrap(ExecutionException e) throws QuantisException {
Throwable t = e.getCause();
if (t instanceof QuantisException) {
throw (QuantisException) t;
}
throw new RuntimeException(e);
}
}