Reputation: 21281
I have specific number of threads, say 5 threads: A, B, C, D, and E.
I'd love to know what are some specific approaches to design a communication interface between these threads such that the receiver thread can distinguish messages from different senders. Also, each thread should also be able to send message to itself.
For example, can I design each thread to have multiple BlockingQueues
, one for each sender thread? Also, each thread has a list of receivers where it can send message to? Is it recommended?
What is the best/reasonable way to implement this in java?
Upvotes: -1
Views: 292
Reputation: 8404
It can depend on what "other things" one might want to do in the future with the code.
If these threads, and this program, are only ever going to be a single process written in Java with no interaction with anything else, then using an in-language facility such as those mentioned by JumpandSpintoWin
can be the best way to go. I'm not a Java programmer, but I'm presuming that things like a TransferQueue
are Java internal queues that move objects by reference, rather than by copy. That is desirable, because it doesn't matter how large the object is; it will be the fastest possible transfer between threads.
However, if you have the prospect that these threads may end up having to cooperate across processes, or indeed across machines, then some other message passing queue technology may be worth a while. A popular, language and platform agnostic choice at the moment is ZeroMQ
. Such things pass objects by copy, not by reference, so if it's all in-process (and only ever going to be 5 threads in the same process), it will not be as fast. But if you do have to grow this application to "spread out" across processes, languages, platforms, ZeroMQ is an excellent choice.
It passes objects by copy - actually, you have to serialise objects to a buffer, turn that into a ZeroMQ message, pass that message to a destination, deserialise it to build a fresh object in the destination. For large amounts of data, that obviously could take some time. But, this is why it also copes with inter-process and inter-computer distributions. And if you pick the right serialiser (e.g. Google Protocol Buffers), you get language independence too (as in, both ZeroMQ and GPB can be got for many languages).
It can be worth it though for other reasons; you'd be using Actor Model program architecture, which comes with some nice attributes in multi-threaded applications. Because each thread is dealing with its own private copy of objects, it's unlikely that you run into issues such as two threads trying to access the same object at the same time. So you don't need to have locks like semaphores, or mutexes on objects. It can be far, far easier to debug, review and fix Actor Model multi-threaded code than code relying on object locking, atomics, etc. Actor model can bring its own problems such as live lock and dead lock, but once one understands those one can be on the look out for whether or not you're creating the potential for them to occur.
There is an evolution of Actor model programming called Communicating Sequential Processes - CSP. This is a similarly old concept, but has the added quality that if you've accidentally created an architecture that can dead lock, it will dead lock every single time (whereas Actor Model architectures might not until a network gets a bit busy). CSP has made something of a comeback, and is now a core part of the Go language, and readily available in Rust too. Being part of the languages, CSP in those instances is implementing "message passing" like concepts (CSP's channels), but are in fact passing objects by reference and not copying them. There is a CSP implementation for JAVA, see Kent University's very old fashioned web page for the home of JCSP. See also this answer.
On modern CPU architectures, creating a thread-local copy of data isn't so very different to accessing the original data in memory connected to a different CPU / CPU core. Creating the copy, or accessing the remote data, both involve transferring data across a CPU interconnect of some sort (e.g. QPI in oldish Intel speak), and placing it in core-local cache. That's not something to rely on - the underlying OS probably has a handle on what memory a thread is accessing and makes sure to schedule it on cores close to where that memory is. But you can see that it's not always clear that a copy is a bad thing (from an overall speed point of view).
Upvotes: 0
Reputation: 187
You want a Message Passing Interface between each thread. I would structure the program by creating the message passing interfaces first, then constructing thread A's class and thread B's class and passing the interface as an argument to both. Then start the threads.
For Java, the TransferQueue
class looks like a good choice. If you don't need some of its features you can also just use the ConcurrentLinkedQueue
. Use two for bi-directional communication.
Upvotes: 3