eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI EA (cat= Testing)
announcement - icon

Distributed systems often come with complex challenges such as service-to-service communication, state management, asynchronous messaging, security, and more.

Dapr (Distributed Application Runtime) provides a set of APIs and building blocks to address these challenges, abstracting away infrastructure so we can focus on business logic.

In this tutorial, we'll focus on Dapr's pub/sub API for message brokering. Using its Spring Boot integration, we'll simplify the creation of a loosely coupled, portable, and easily testable pub/sub messaging system:

>> Flexible Pub/Sub Messaging With Spring Boot and Dapr

1. Introduction

We’ve previously looked at inter-process communication (IPC) and seen some performance comparisons between different methods. In this article, we’re going to look at how we can implement some of these methods in our Java applications.

2. What Is Inter-Process Communication?

Inter-Process Communication, or IPC for short, is a mechanism by which different processes can communicate. This can range from various processes that form the same application, to different processes running on the same computer, and other processes spread across the internet.

For example, some web browsers run each tab as a different OS process. This is done to keep them isolated from each other but does require a level of IPC between the tab process and the main browser process to keep everything working correctly.

Everything we look at here will be in the form of message passing. Java lacks standard support for shared memory mechanisms, though some third-party libraries can facilitate this. As such, we’ll think about a production process that sends messages to a consumption process.

3. File-Based IPC

The simplest form of IPC that we can achieve in standard Java is simply using files on the local file system. One process can write a file, while the other can read from the same file. Anything that any process does using the file system outside the process boundary can be seen by all other processes on the same computer.

3.1. Shared Files

We can start by having our two processes read and write the same file. Our producing process will write to a file on the file system, and later, our consuming process will read from the same file.

We do need to be careful that writing to the file and reading from the file don’t overlap. On many computers, file system operations aren’t atomic, so if the writing and reading are happening simultaneously, the consuming process may get corrupt messages. However, if we can guarantee this — for example, using filesystem locking — then shared files are a straightforward way to facilitate IPC.

3.2. Shared Directory

A step up from sharing a single, well-known file is to share an entire directory. Our producing application can write a new file into the directory every time it needs to, and our consuming application can detect the presence of a new file and react to it.

Java has the WatchService API in NIO2 that we can use for this. Our consuming process can use it to watch our target directory, and whenever it notifies us that a new file has been created, we can react to it:

WatchService watchService = FileSystems.getDefault().newWatchService();

Path path = Paths.get("pathToDir");
path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);

WatchKey key;
while ((key = watchService.take()) != null) {
    for (WatchEvent<?> event : key.pollEvents()) {
        // React to new file.
    }
    key.reset();
}

Having done this, our producing process needs to create appropriate files in this directory, and the consuming process will detect and process them.

Remember, though, that most filesystem operations aren’t atomic. We must ensure that the file creation event is only triggered when the file is completely written. This is commonly done by writing the file into a temporary directory and then moving it into the target directory when finished.

On most filesystems, a “move file” or “rename file” action is considered atomic as long as it happens within the same filesystem.

3.3. Named Pipes

So far, we’ve used complete files to pass our messages between processes. This requires that the producing process has written the entire file before the consuming process reads it.

Named Pipes are a particular type of file we can use here. Named pipes are entries on the file system but don’t have any storage behind them. Instead, they act as a pipeline between writing and reading processes.

We start by having our consuming process open the named pipe for reading. Because this named pipe is presented as a file on the filesystem, we do this using standard file IO mechanisms:

BufferedReader reader = new BufferedReader(new FileReader(file));

String line;
while ((line = reader.readLine()) != null) {
    // Process read line
}

Everything that’s written to this named pipe will then be immediately read by this consuming process. This means that our production process needs to open this file and write it as normal.

Unfortunately, we don’t have a mechanism to create these named pipes in Java. Instead, we need to use standard OS commands to create the file system entry before our program can use it. Exactly how we do this varies by operating system. For example, on Linux, we’d use the mkfifo command:

$ mkfifo /tmp/ipc-namedpipe

And then, we can use /tmp/ipc-namedpipe in our consuming and producing processes.

4. Network-Based IPC

Everything we’ve seen has revolved around the two processes sharing the same filesystem. This means that they need to be running on the same computer. However, in some cases, we wish to have our processes communicate with each other regardless of the computer they’re running on.

We can achieve this by using network-based IPC instead. Essentially, this is just running a network server in one process and a network client in another.

4.1. Simple Sockets

The most obvious example of implementing network-based IPC is to use simple network sockets. We can either use the sockets support in the JDK or rely on libraries such as Netty or Grizzly.

Our consuming process would run a network server that listens on a known address. It can then handle incoming connections and process messages as any network server would:

try (ServerSocket serverSocket = new ServerSocket(1234)) {
    Socket clientSocket = serverSocket.accept();

    PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
    BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

    String line;
    while ((line = in.readLine()) != null) {
        // Process read line
    }
} 

The producing processes can then send network messages to this to facilitate our IPC:

try (Socket clientSocket = new Socket(host, port)) {
    PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
    BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

    out.println(msg);
}

Notably, compared to our file-based IPC, we can more easily send messages in both directions.

4.2. JMX

Using network sockets works well enough, but there’s a lot of complexity that we need to manage ourselves. As an alternative, we can also use JMX. This technically still uses network-based IPC, but it abstracts the networking away from us, so we’re working only in terms of the MBeans.

As before, we’d need a server running on our consuming process. However, this server is now our standard MBeanServer from the JVM rather than anything we do ourselves.

We’d first need to define our MBean itself:

public interface IPCTestMBean {
    void sendMessage(String message);
}

class IPCTest implements IPCTestMBean {
    @Override
    public void sendMessage(String message) {
        // Process message
    }
}

Then, we can provide this to the MBeanServer within the JVM:

ObjectName objectName = new ObjectName("com.baeldung.ipc:type=basic,name=test");

MBeanServer server = ManagementFactory.getPlatformMBeanServer();
server.registerMBean(new IPCTest(), objectName);

At this point, we’ve got our consumer ready.

We can then use a JMXConnectorFactory instance to send messages to this server from our producing system:

JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1234/jmxrmi");
try (JMXConnector jmxc = JMXConnectorFactory.connect(url, null)) {
    ObjectName objectName = new ObjectName("com.baeldung.ipc:type=basic,name=test");

    IPCTestMBean mbeanProxy = JMX.newMBeanProxy(jmxc.getMBeanServerConnection(), objectName, IPCTestMBean.class, true);
    mbeanProxy.sendMessage("Hello");
}

Note that for this to work, we need to run our consumer with some additional JVM arguments to expose JMX on a well-known port:

-Dcom.sun.management.jmxremote=true
-Dcom.sun.management.jmxremote.port=1234
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

We then need to use this within the URL within the client for it to connect to the correct server.

5. Messaging Infrastructure

Everything we’ve seen so far is a relatively simple means of IPC. At a certain point, this stops working as well. For example, it assumes that there is only one process consuming messages — or that the producers know exactly which consumer to talk to.

If we need to go beyond this, we can integrate with dedicated messaging infrastructure using something like JMS, AMPQ, or Kafka.

Obviously, this is on a much larger scale than we’ve been covering here — this would allow an entire suite of producing and consuming systems to pass messages between each other. However, if we need this kind of scale, then these options do exist.

6. Conclusion

We’ve seen several different means of IPC between processes and how we can implement them ourselves. This has covered a range of scales, from sharing an individual file to an enterprise-level scale.

Next time you need to have multiple processes communicating with each other, why not consider some of these options?

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)