Photo by Evi Radauscher on Unsplash


When describing I/O, the terms non-blocking and asynchronous are often used interchangeably, but there is a significant difference between them. In this article are described the theoretical and practical differences between non-blocking and asynchronous sockets I/O operations in Java.

Sockets are endpoints to perform two-way communication by TCP and UDP protocols. Java sockets APIs are adapters for the corresponding functionality of the operating systems. Sockets communication in POSIX-compliant operating systems (Unix, Linux, Mac OS X, BSD, Solaris, AIX, etc.) is performed by Berkeley sockets. …

Photo by Silas Baisch on Unsplash


The CompletableFuture API is a high-level API for asynchronous programming in Java. This API supports pipelining (also known as chaining or combining) of multiple asynchronous computations into a single result without the mess of nested callbacks (“callback hell“). This API also is an implementation of the future/promise concurrency constructs in Java.

Since Java 5 there is a much simpler API for asynchronous programming: the Future interface and its base implementation, the FutureTask class. The Future interface represents the result of asynchronous computation and has only a few methods:

  • to check if a task is completed or canceled
  • to cancel a…

Photo by Joanna Kosinska on Unsplash


The WebSocket protocol is designed to overcome the architecture limitations of HTTP-based solutions in simultaneous bi-directional communication. Most importantly, WebSocket has another communication model (simultaneous bi-directional messaging) than HTTP (request-response).

WebSocket works over TCP that allows transmitting of two-way streams of bytes. WebSocket provides thin functionality on top of TCP that allows transmitting binary and text messages providing necessary security constraints of the Web. But WebSocket does not specify the format of such messages.

WebSocket is intentionally designed to be as simple as possible. To avoid additional protocol complexity, clients and servers are intended to use subprotocols on top of…

Photo by Neven Krcmarek on Unsplash


The HTTP protocol is a request-response protocol. That means that only a client can send HTTP requests to a server. A server can only service HTTP requests by sending back HTTP responses, but a server can not send unrequested HTTP responses to a client.

This is because HTTP was originally designed for request-response resources transfer in distributed hypermedia systems but not for simultaneous bi-directional communication. To overcome these architecture limitations are used several HTTP mechanisms (grouped under the unofficial name Comet) that are often complicated and inefficient.

The WebSocket protocol is designed to replace existing workaround HTTP mechanisms and provide…

Photo by Dustin Humes on Unsplash


Barrier synchronizers (barriers) are a kind of synchronizer that ensures that any threads must stop at a certain point and cannot proceed further until all other threads reach this point.

By purpose, barriers can be grouped into the following categories:

  • entry barriers, that prevents threads from starting processing
  • exit barriers, that waiting for all threads to finish processing

Barriers also can be grouped by the number of iterations (one-time or cyclic) and by the number of parties/threads (fixed or variable).

In Java 7+ there are 3 predefined barrier classes: CountDownLatch, CyclicBarrier, Phaser.

The CountDownLatch class

The CountDownLatch class is a one-time barrier that…

Photo by Vincent Guth on Unsplash


There are no simple, general-purpose methods to implement asynchronous server-to-client communication in web applications with acceptable performance.

HTTP is a request-response protocol in the client-server computing model. To start an exchange, a client submits a request to a server. To finish the exchange, the server returns a response to the client. The server can send a response to only one client — the one that made the request. In the HTTP protocol, a client is the initiator of messages exchange.

There are cases when a server should be the initiator of exchange. One of the methods to implement this is…

Photo by Christian Holzinger on Unsplash


In small applications to execute each task (Runnable object) is created a new thread (Thread object). When the task is completed, the thread is terminated as well. But in large applications overhead of threads creation and termination can be significant. Such overhead can be reduced by reusing the same threads for the execution of many tasks. For that purpose are used executors and thread pools. An executor is a design pattern that provides API for task executions and hides its implementation. A thread pool is one of the executor implementations that uses a pool of threads for task execution.


Photo by Paweł Czerwiński on Unsplash


There are several ways to reduce Stream as a sequence of input elements into a single summary result. One of them is to use implementations of Collector interface with Stream.collect(collector) method. It’s possible to implement this interface explicitly, but it should start with studying its predefined implementations from Collectors class.

Classification of predefined collectors

There are 44 public static factory methods in Collectors class (up to Java 12) that return predefined implementations of Collector interface. To understand them better, it’s rational to divide them into categories, for example:

  • collectors to collections:
  • 1) regular collectors to collections
  • 2) collectors to unmodifiable collections
  • downstream-designed collectors:
  • 1)…

Aliaksandr Liakh

Senior Software Engineer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store