Java is 25 years old now and what an impressive career it has done, from an embedded language to digital devices like televisions, to support the business core of large companies around the world.
Java has created a lot of mixed feelings in the technology industry, from how “difficult” it is to learn it to some performance constraints in high throughput systems.
In this post, I will show you a summary of the past, present and future of Java, and why Java will stay relevant for the decades to come, trying to answer the following concerns:
- Has Java been slow to change and improve to the new contexts?
- Has Oracle affected Java after he acquired it 10 years ago? Is the Java ecosystem closed by Oracle trademark?
- Has Java had a good performance for high throughput and demanding businesses?
Let’s get into it.
Java Evolves Faster Than Ever
Evolving fast is important in the technology industry. Every day, new problems and solutions show up, and if your language/framework doesn’t evolve fast, it will be replaced.
At the timing of writing this post, Java has 14 versions, which were released as follows:
|1.0||January 23, 1996||0||Sun|
|1.1||February 19, 1996||0||Sun|
|1.2||December 8, 1998||2||Sun|
|1.3||May 8, 2000||2||Sun|
|1.4||February 6, 2002||2||Sun|
|5||September 30, 2004||2||Sun|
|6||December 11, 2006||2||Sun|
|7||July 28, 2011||5||Oracle|
|8||March 18, 2014||3||Oracle|
|9||September 21, 2017||3||Oracle|
|10||March 20, 2018||1||Oracle|
|11||September 25, 2018||0||Oracle|
|12||March 19, 2019||1||Oracle|
|13||September 17, 2019||0||Oracle|
|14||March 17, 2020||1||Oracle|
As you see, Java evolved quite fast from its first 6 versions, releasing a new version every 2 years, when Sun Microsystems was the owner. However, from the 6th version to the 7th version, it took 5 years (a lot of time for the technology industry).
Between those two versions, great (and concern) events happened:
- In 2006, Sun Microsystems open source the Java Virtual Machine (JVM) specification, creating the OpenJDK community, a free implementation of the JVM. This opened Java to the world, creating a full ecosystem of open source projects and developers around the world. (We will discuss this in detail later).
- In 2009, Oracle bought Sun Microsystems, creating a lot of concern around the technology industry for the future of Java, and this slowed down the Java evolution. Some developers believed that Oracle would charge for Java use, and that, will kill Java forever.
Oracle released Java slowly, every 3 years, from the 7th version to the 9th version. However, the 8th and 9th versions were game-changers. In the case of Java 8, it included things the industry thought Java would not ever have, like Functional Interfaces, Lambda Expresiones, Streams, and a new Java Time API.
Besides, Java 9 brought Java modules, to allow users to plug and play new features to the JDK easily. For instance, the OpenJDK team creates preview features, so developers can use them in real contexts and give back feedback, before those features are included by default in the JDK. Modules gave Java a push to evolve faster than before.
After Java 9, you see how fast Java has evolved1, with a release cadence of 6 months, adding new features, previews, and improvements in its core. Java 9 opened the door to the new release cadence strategy, allowing the community to propose new JDK features, using the JEP (JDK Enhancement Proposals) process, creating an ecosystem of innovation that evolves each day.
Now, it is not only about the Java new features and evolution, it is also about 25 years of a technology ecosystem, as we discuss as follows.
Large Java Ecosystem
Oracle owns the Java trademark, however, the ecosystem around Java is huge as some Github statistics show2:
Hundreds of thousands of repositories, commits, issues, created by thousands of developers around the world, focusing the efforts on several fields, from Data Science and Big Data3, to high throughput applications. Developers show that Java is useful to solve any problem, it doesn’t matter the context, performance requirements or business complexity.
Plus, the 2020 Stack Overflow survey4 about the Most Popular Technologies for developers around the world, shows how Java by itself is one of the most used:
As you see, Java is the 4th most popular language in the world, however, there is a trick here, what about the JVM languages5? Let’s summarize all of them:
The impact of Java and the JVM is not only as a language, also, as facilitator of new languages.
Developers use Java, but what about companies? well, companies around the world trust the JVM for its critical systems, like Twitter, which has moved part of the platform to Java, showing that it is possible to create highly scalable and performance systems using the JDK6. Twitter has 126 million daily users7.
Besides, Netflix, another company using Java intensibily, uses Java from runtime containers, libraries and services, to automated scalable multimedia ingest and encoding, all of them oriented to work on a cloud environment and microservices architecture8.
It is not only how large companies use Java, but it is also how they collaborate to improve Java and its ecosystem. For instance, Twitter, as they rely a lot on Java, they started to collaborate over OpenJDK.
Also Netflix, released as open source its core frameworks for Cloud Computing and Microservices architectures based on Java, between them: Hystrix, Eureka, Ribbon, and Archaius. Those later were included on the Spring Cloud Umbrella.
And there is more, to the surprise of the world, Microsoft announced how they will start to collaborate over the OpenJDK too, furthermore, creating tools for Azure to run Java Cloud Native applications, and adding a Java Microsoft Visual Code to the Java toolset9.
Besides, Microsoft bought Github.com to support from its core the open-source industry, and guess what? Java source code will be moved from OpenJDK repository to Github.com10, enduring the Java and Microsoft relationship much more.
Companies and developers, plus open sourcing, have been the perfect mix to create a beautiful ecosystem. Now, which features will the ecosystem bring us next? Let’s see some of the game changers regarding performance and high throughput requirements.
Performance for High Throughput Systems
“Java is slow”, “Java doesn’t work for high throughput systems”, “I cannot use Java in a Cloud Lambda infrastructure, is too slow to start”. Those are just some of the critics we have heard about Java through the years. Some of them are not totally true, and companies like Twitter and Netflix can tell better than me, but, of course, you can always find space to improve, and Java does.
Let’s talk about two game changers for Java performance, Project Loom and Graal.
Scalability and good use of resources like Threads is a well-known concern for Java applications.
Threads in Java are an object of execution, they allow your program to process requests in a concurrent manner, so, as many threads an application has, as many concurrent tasks, an application can handle.
When you start a web project using Java, you usually choose a web server to deploy that project, for instance, Tomcat is a pretty well known one. By default, Tomcat starts a Thread pool of max 200 threads12, which means your application in ideal conditions will be able to handle 200 requests per second. That’s enough for an average business application.
However, what if my business application needs to process 10000 requests per second? Well, we just increase the thread pool from 200 to 10000 right? Sadly, in Java, that is not as easy as it sounds.
Java wraps each Thread object to a real thread over the underlying operating system, and the operating system has a limit of real threads it can create, meaning, your Java application cannot grow more than a fixed amount of threads.
With this problem in mind, the Java community found a way to handle a lot of concurrent requests, with few threads. Those are “reactive” libraries.
Reactive libraries are based over the idea that few threads can handle a lot of concurrent requests, if those threads don’t block, for instance, when calling a database, accessing the file system or doing an HTTP request. If they don’t block, they can be reused over and over.
But, this approach brought consequences:
- The program model changed from imperative to functional programming. From the beginning, Java has been an imperative (“boring”) language, so, changing the programming model has consequences for the language, and for the developers.
- The Java observability features decrease, as debugging and tracing a reactive model is harder than an imperative one. We needed to add more things to get Java working over this model, without losing error observations and detection.
- The Java ecosystem uses blocking by nature, that means, you need to adapt the ecosystem to the new model. The last few years, the Java ecosystem has grown the amount of reactive libraries, but 25 years of blocking libraries cannot be rebuilt in 5 years, so, you will need to coexist with blocking libraries in your non blocking reactive application.
Spring Webflux, Project Reactor, Eclipse Vert.x and Akka, are some examples for reactive frameworks, plus, the ecosystem surrounds them, like reactive database drivers and networking.
You might think: “that sounds right, but, what about Project Loom?”
Well, Project Loom “aims to drastically reduce the effort of writing, maintaining, and observing high-throughput concurrent applications that make the best use of available hardware”, and one of the items is how to improve the performance of Java threads in high throughput concurrent applications13.
At the time of writing this post, Project Loom defined the concept of Virtual Threads, where: “Virtual threads are just threads, but creating and blocking them is cheap. They are managed by the Java runtime and, unlike the existing platform threads, are not one-to-one wrappers of OS threads, rather, they are implemented in userspace in the JDK”.
Well, seems right again, so what? The key here is “creating and blocking them is cheap”, that means, you not only can create thousands of threads but millions of them, so it is cheap to create and block them.
That opens some questions:
- Can you imagine removing the Threads concern from the table when you design a system? You will have millions of them.
- If you can create a lot of threads, will you bother using reactive libraries again?
- How will reactive frameworks use this as an opportunity? Any change brings opportunities, and I would like to see how reactive libraries adapt to this new context.
- Will we give up Java functional programming for imperative again? Of course, imperative programming is easier than functional programming, but should we give up with functional?
I don’t have the answers to those questions, but, I am excited about the opportunities.
Java since the beginning was created to be interoperable over different computer architectures and operating systems, which means “Write Once, Run Anywhere”. To allow interoperability, Java code is compiled to bytecode, which is an intermediate step between Java and a binary executable15.
When you deploy your Java application in a JVM, a second translation happens, from bytecode, to a binary executable, allowing the application to run over the underlying machine. This process is done by the Just In Time compiler (JIT)16.
However, JIT doesn’t optimize at maximum the binary executable, instead, JIT just creates enough optimized binary to start.
This means, when you start a Java program, that program performs only with enough optimized code. But that’s not all, JIT optimizes the Java program when we start to use the application, which means, any time you invoke or use a Java code in your program, as a client, JIT learns, and optimizes the most used bytecode, the hotspots, improving the performance on the fly, while the Java program runs.
An ongoing learner compiler is an awesome concept, but it has a downside: When your Java application stops, the JIT optimizations are gone, so, JIT will need to learn again everything. The reason for this is because it creates a balance between interoperability and performance.
What if you want the whole optimization power since the beginning? What if you know exactly in which underlying platform your Java program will run? Well, Graal uses these assumptions to improve Java performance applications.
GraalVM allows you to jump from Java code to a binary executable, using ahead-of-time compiler for native images. Ahead of time compiler compiles the program directly from Java code to a binary executable, in contrast to the Just In Time compiler, which means you will have the whole power of the underlying system from the beginning.
You might think: “Hold on, you said the main goal of Java is to be interoperable, so, to create a binary executable, you will need to know which underlying system your Java application will run, and that’s not good”. You are right, but, we are now in the world of containers like Docker, so, when you deploy a Java application over a Docker image, you already know which underlying operative system will be used.
But why is this important? Well, you will get the following:
- Java runs faster, allowing high throughput. As the Java application don’t need to compile hot spots, those resources are now used by the program itself, besides, the binary executable is totally native, so it uses the whole power of the underlying operative system.
- Java starts faster, allowing a fast ramp up the first time you start it. This is pretty useful if you have your Java program in a Serverless infrastructure.
- Less memory footprint. You don’t need to trace the hot spots any more, so those resources are released.
Graal adds a whole set of opportunities for the Java ecosystem and I hope to see them.
Final Thought: Java Developers, Be Proud
Java is dead, long live to Java. Java is more relevant today than ever, moving faster, evolving with the user’s needs in mind, and being supported by a large open-source community, which includes large organizations like Twitter, Netflix and Microsoft.
Java is here and will stay for a long time, enjoy this moment, and be proud to be a Java developer today.
- Update and FAQ on the Java SE Release Cadence
- Github search
- The 25 greatest Java apps ever written
- Stackoverflow 2020 survey
- Stackoverflow 2020 survey JVM
- Go Java at Twitter
- Twitter daily user base
- Java and Open source at Netflix
- Java At Microsoft: From OpenJDK to Azure Spring Cloud
- JEP 369: Migrate to GitHub
- Project Loom
- The Executor (thread pool)
- State of Loom May 2020
- Project Leyden
- JIT (Just-In-Time) compilator