java - Grails/java 单资源池线程队列

标签 java grails threadpool

我正在尝试设置一个从设备 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/

相关文章:

java - hive 和 spark 分布的 hive thrift 服务器之间的区别

java - 如何在 Android 中发出 httppost 请求?

grails - 如何在Oracle 12c上使用Grails 2.2.4?

authentication - Grails:如何获取当前登录用户的用户名,这需要什么导入?

java - Oracle Form 频繁挂起

java - 用户注册与电子邮件验证

java - 在 Java 中运行 MySQL 查询?

grails - 通过gradle任务传递grails run-app的命令行参数

c - pthread线程池场景

python - 使用 pool.map 使用一个参数和 self : TypeError: map() missing 1 required positional argument: 'iterable' 调用类中的函数