The prototype application is designed to perform several tasks in parallelprocessing events received via the UI, performing computations required (say, to playback or compress audio), and sending and receiving data over the network. This is a wonderful application for a parallel machine because, well, these operations really can be performed in parallel.
Java supports this kind of parallelism via its threading mechanisms, and so its APIs for most operations, such as IO, are blocking. This isn't the only possible approach; many traditional applications use an event-driven model that can multiplex events from multiple sources, including UI and nonblocking IO facilities. However, while an event loop can give the illusion of doing several things at once, it is really only one event at a time that's being processed. That didn't matter much when a CPU could only do one thing at a time, but Java's approach is better suited to increasing hardware parallelism.
The essential threading requirement imposed by OSGi is that applications keep track of all of these threads operating in parallel. This arises from OSGi's dynamic nature; OSGi wants to be able to start, stop, load, and unload bundles as necessary or as directed. That implies that a bundle must respond to a command to stop, and stopping must be complete: There cannot be threads that are forgotten still tying up resources the bundle was supposed to have released.
This OSGi design arises from its target set-top environment where bundles from various sourcesincluding possibly different vendorsneed to cooperate. When building a desktop application on OSGi (possibly transitively, by building first on Eclipse), this level of dynamism might seem excessive. Even a desktop application, however, might be composed of different bundles. It might support plug-ins built by third parties, and any of these might need to be updated. OSGi's dynamism might be essential in embedded devices but it certainly isn't useless on the desktop.