我正在尝试设置一个从设备 Quantis - 量子随机数生成器
提供真随机数的服务器。我使用 Grails 框架构建了 Web 应用程序,并在 Ubuntu
上的 Tomcat
服务器上运行。
由于只有 1 个设备,我必须安排访问它的线程,对吗?因此,我在调用该设备的函数(ReadInt、ReadDouble、ReadFloat
)上设置了信号量(使用 1 个资源)。包含这些函数的对象称为 Quantis,存储在 Grails 应用程序的 Java 源包中,它作为单例实现;然后 Controller 将调用该对象的实例及其函数。然后,每个函数都会调用系统上的 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; } } }
最佳答案
首先,“它会崩溃”对于所发生的情况的描述很糟糕。有什么异常(exception)吗?到底发生了什么?
第二,您确定需要同步API的访问吗?如果它提供 Java API,则很有可能该 API 已经同步,并且不需要您的信号量。
第三,如果你获取了一个信号量,你应该在finally block 中释放它。这保证了无论 try block 内发生什么,它都会被释放:
ticket.acquire();
try {
...
}
catch (...)
finally {
ticket.release();
}
第四:我不明白 while(true)
循环的意义。它循环的唯一时间是出现 InterruptedException 时。 InterruptedException 正是用于向线程发出信号,指示它应该尽快停止执行。所以你的方法应该抛出这个异常而不是吞掉它。
最后,您应该学习 Java 命名约定并遵守它们。方法以小写字母开头。
如果您确实需要同步访问,那么我将如何重写该方法:
public int readInt(int min, int max) throws QuantisException, InterruptedException {
ticket.acquire();
try {
return quantisReadScaledInt(deviceType.getType(), deviceNumber, min, max);
}
finally {
ticket.release();
}
}
如果要确保只有一个线程可以访问 native 库函数,请使用这样的类:
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);
}
}
关于java - Grails/java 单资源池线程队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8960617/