我有一个Web服务器服务,客户端请求智能卡计算并获得结果.可用的智能卡号可以在服务器正常运行时间内减少或增加,例如我可以从阅读器中物理添加或删除智能卡(或许多其他事件......例如异常等).
智能卡计算可能需要一段时间,因此如果存在对Web服务器的并发请求,我必须优化这些作业以使用所有可用的智能卡.
我想过使用智能卡线程池.至少对我而言,不寻常的是,池应该改变其大小,而不是取决于客户端请求,而只取决于智能卡的可用性.
我研究过很多例子:
BlockingQueue:存储请求和停止线程等待某事做的好看.
FutureTask:我可以使用这个类让客户端等待它的答案,但是哪种类型的执行器应该完成任务?
ThreadPoolExecutor:看起来我需要什么,但有了这个我不能改变池大小,而且每个线程都应该链接到一个智能卡插槽.如果我可以更改池大小(在插入智能卡时添加线程并在移除智能卡时删除线程)以及我是否可以为每个线程分配特定智能卡,这可以是一种解决方案.
这是智能卡控件,每个智能卡有一个SmartcardWrapper,每个智能卡都有自己的插槽号.
public class SmartcardWrapper{ private int slot; public SmartcardWrapper(int slot) { this.slot=slot; } public byte[] compute(byte[] input) { byte[] out=new byte[]; SmartcardApi.computerInput(slot,input,out); //Native method return out; } }
我尝试使用每个智能卡一个线程创建一个线程池:
private class SmartcardThread extends Thread{ protected SmartcardWrapper sw; public SmartcardThread(SmartcardWrapper sw){ this.sw=sw; } @Override public void run() { while(true){ byte[] input=queue.take(); byte output=sw.compute(input); // I have to return back the output to the client } } }
每个人在同一输入队列中等待某事:
BlockingQueuequeue=new BlockingQueue ();
但是如何将智能卡线程的输出返回给webserver-client呢?这让我觉得BlockingQueue不是我的解决方案.
如何解决这个问题?我应该遵循哪种并发模式?为每个智能卡分配一个线程是否正确或我是否可以简单地使用信号量?
你的假设:
ThreadPoolExecutor:看起来我需要什么,但有了这个我不能改变池大小,而且每个线程都应该链接到一个智能卡插槽.
是不正确的.
You can set thread pool size dynamically.
看看下面的ThreadPoolExecutor API
public void setMaximumPoolSize(int maximumPoolSize)
设置允许的最大线程数.这将覆盖构造函数中设置的任何值.如果新值小于当前值,则当下一个空闲时,多余的现有线程将被终止.
public void setCorePoolSize(int corePoolSize)
设置核心线程数.这将覆盖构造函数中设置的任何值.如果新值小于当前值,则当下一个空闲时,多余的现有线程将被终止.如果需要更大,则新线程将启动以执行任何排队任务.
Core and maximum pool sizes:
A ThreadPoolExecutor
将根据corePoolSize
和设置的边界自动调整池大小maximumPoolSize
.
当在方法中提交新任务execute(java.lang.Runnable)
且corePoolSize
运行的线程少于正在运行时,即使其他工作线程处于空闲状态,也会创建一个新线程来处理该请求.
如果运行的线程数多于corePoolSize
但少于maximumPoolSize
线程,则仅当队列已满时才会创建新线程.
通过设置maximumPoolSize
基本上无限制的值,例如Integer.MAX_VALUE
,允许池容纳任意数量的并发任务.但我不建议拥有那么多线程.请谨慎设置此值.
最典型的情况是,核心和最大池大小仅在构造时设置,但也可以使用setCorePoolSize(int
)和动态更改setMaximumPoolSize(int)
.
编辑:
为了更好地利用线程池,如果知道最大卡数为6,则可以使用
ExecutorService executor = Executors.newFixedThreadPool(6);
要么
您是否考虑过使用Apache Commons Pool?
您需要维护一个SmartcardWrapper对象池,其中每个SmartcardWrapper将代表一个物理SmartCard.无论何时需要进行新计算,都要从池中借用对象,进行计算并返回池中的对象,以便下一个线程可以重用它.
池本身是线程安全的,并在没有可用对象时阻塞.您需要做的就是实现一个api来向池中添加/删除SmartcardWrapper对象.