我正在使用OSGI框架来创建一个严重依赖于数据包处理的应用程序。
每个捆绑包处理一个包,然后将其发送到下一个包。我想要的是每个捆绑包都是并行的。所以我想让每个bundle都运行在它自己的Thread或多个Threads中。 “问题”是OSGI并不真正支持多线程。在同一个JVM上运行的每个bundle只运行在1个Thread中,因此它遵循同步模型。
我的想法: 所以应用程序的性质就像生产者消费者一样。 Bundle A提供的服务有一个用于将包发送给A的方法,我们称之为方法ain。 Bundle B也有同样的设置,C也是如此。他们都有aa / b / cout方法,在这个方法中他们使用下一个bundle的服务,所以在A.aout你会像这样调用bin:bservice.bin(package )。
所以每个bundle都是一个消费者和数据包的生产者,这让我觉得使用ExecutorService和BlockingQueues可能会有效,但我不太确定如何在bundle之间“正确”实现这个,并且所有的他们既是消费者又是制片人我不太确定这是否是解决这个问题的最好方法。
我希望你们能提供帮助和/或有任何建议。
- 编辑 -
捆绑A. AServiceImplementation
public class AServiceImplementation implements AService {
private BService bservice;
public void bindBService(BService service) {
bservice = service;
System.out.println("bundle gateway bound to b service");
}
public void unbindBService(BService service) {
this.bservice = null;
}
public void process(int id) {
bservice.transmitIn(id);
}
}
捆绑B. BServiceImplementation
public class BServiceImplementation implements BService {
private CService cservice;
public void bindCService(CService service) {
cservice = service;
System.out.println("bundle gateway bound to b service");;
}
public void unbindCService(CService service) {
this.cservice = null;
}
public void transmitIn(int id){
// So if I would implement it THIS is where I would assign the data to
// a thread to get it processed in the process method.
// but doesn't that make THIS method, transmitIn a bottleneck since all packages
// need to pass through here?
process(id);
}
public void process(int id) {
// Lots of processing happens here
}
}
我真的不明白如何使它成为例如bundle A通过transmitIn方法将数据传输到bundle B而没有transmitIn是一个瓶颈,因为我将'workdistribution'设置为该方法中的不同线程(如上面的代码所示)
答案 0 :(得分:9)
在您的示例中,所有处理都将在初始调用方线程上进行,该线程调用AServiceImplementation。如果你想并行处理,你可以为你提交的每个任务使用执行程序,这就是Executors派上用场的模式。这使处理异步,因此您没有返回值。注意,处理将受到您提供的Executor中可用线程数的限制。您还必须非常小心地编写处理代码,以便为非局部变量处理正确的同步。
另一种方法是排队。每个服务调用都会创建一个包含任务信息的对象,然后将该对象发布到阻塞队列中。在OSGi激活器中,您创建一个读取队列并对其进行处理的线程。在这个模型中,您可以在不担心(过多)并发性的情况下进行处理,因为所有处理总是在同一个线程中进行。出于性能原因,您可以启动多个线程,但处理起来要困难得多。
但是,我的建议是跳过此优化并尽可能简化您的系统。如果它运行,并且您发现存在性能问题,则可以尽早开始担心这些问题。根据您目前的理解水平,我担心您有机会为“可能”的问题创建一个高度复杂的解决方案。
答案 1 :(得分:4)
'问题'是OSGI并不真正支持多线程。在同一个JVM上运行的每个bundle只运行在1个Thread中,因此它遵循同步模型。
抱歉,这是一个完全的误解。让我引用OSGi Core规范,第4.2.7节:
OSGi框架在多线程环境中运行。框架启动后,它 将启动捆绑包,这些捆绑包将被激活。激活的包通常会启动后台 线程或对来自其他bundle的事件做出反应。也就是说,在start方法返回之后,框架 已经转移到ACTIVE状态,许多捆绑包可能在不同的线程上忙碌。
换句话说,您可以自由地创建适合您需求的任何线程解决方案。这不是OSGi问题。
更新:
您的服务实现可以像这样共享ExecutorService:
public class BServiceImplementation implements BService {
private ExecutorService executorService;
private CService cservice;
public void bindCService(CService service) {
cservice = service;
System.out.println("bundle gateway bound to b service");
}
public void bindExecutorService(ExecutorService executorService) {
this.executorService = executorService;
}
public void unbindCService(CService service) {
this.cservice = null;
}
public void transmitIn(final int id) {
executorService.submit(new Runnable() {
@Override
public void run() {
process(id);
}
});
}
public void process(int id) {
// Lots of processing happens here
}
}
然后让另一个bundle将ThreadPoolExecutor暴露为ExecutorService。
答案 2 :(得分:1)
我想知道你是否不能在你的激活方法中使用以下代码行:
public void activate(){
new Thread(this).start();
}
现在你只需要捆绑Runnable,并实现run()方法。在这种运行方法中,您可以让捆绑的消费者端等待新任务。
然后让每个消费者(它是通信捆绑的服务端)定义一个BlockingQueue。当bundle(producer-end)绑定到某个服务时,您还要确保保留对此队列的引用。这样每个捆绑包应该只有一个队列。