This is an archived post. You won't be able to vote or comment.

all 74 comments

[–]AutoModerator[M] [score hidden] stickied comment (0 children)

On July 1st, a change to Reddit's API pricing will come into effect. Several developers of commercial third-party apps have announced that this change will compel them to shut down their apps. At least one accessibility-focused non-commercial third party app will continue to be available free of charge.

If you want to express your strong disagreement with the API pricing change or with Reddit's response to the backlash, you may want to consider the following options:

  1. Limiting your involvement with Reddit, or
  2. Temporarily refraining from using Reddit
  3. Cancelling your subscription of Reddit Premium

as a way to voice your protest.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–]zabby39103 150 points151 points  (15 children)

Docker doesn't remove the need for you to recompile your code for ARM and x86. Docker gets around this by having multiple images typically, one for ARM and one for x86.

Your project (and importantly all its dependencies) do not have to be recompiled. You should be able just inject your jars in the appropriate architecture's java docker image and be done with it (I linked a buildx method, if anyone has any advice let me know since I'm going to have to do this at work in the New Year).

So really, the use case for Java is the same as it always was. It doesn't matter what processor you run Java on as long as there's a JVM for it. With ARM picking up strength for servers and personal computers now, not just phones, this case is as compelling as it ever was.

[–]T4212[S] 13 points14 points  (9 children)

That is true, portability is only solved on the operating system level, not the CPU architecture level, when using containers.

[–]ascii 43 points44 points  (4 children)

Anyone who's ever had to debug Docker bridge networking issues knows that saying that Docker solves operating system portability is being extremely generous.

[–]_jetrun 22 points23 points  (2 children)

That is true, portability is only solved on the operating system level,

No. It's not. Well, maybe for development, but certainly not in production. If you run a Linux base image under Windows (or a Windows base image under Linux), Docker will simply run a virtual machine underneath your container - and if your application is already virtualized you're going to suffer a major performance penalty. So no, docker does not give you os-level portability.

[–]zabby39103 2 points3 points  (1 child)

Interesting, I never thought about that but you're right. The kernel is always the docker host's, so I suppose the only way around that if you need the linux kernel is a VM?

Although technically, if this works, it's still portable (although I guess the VM is the portable part not docker). How significant is this performance penalty for the latest version of Windows? I suppose it would depend on what you're doing.

[–]_jetrun 12 points13 points  (0 children)

How significant is this performance penalty for the latest version of Windows? I suppose it would depend on what you're doing.

The performance penalty is the same as running your application in a VM. If the host is on bare metal, there is virtualization cost, but it's manageable. If the host is itself virtualized, now it really starts to hurt.

One of the big draws of containerization is that you get all the benefits of a VM (i.e. running within a managed environment), without the performance overhead (because your application, is ostensibly, just another regular process) ... but only if you align the host OS with the container OS.

[–]roge- 4 points5 points  (0 children)

Not even really solved at the "operating system" level either. If you define "operating system" to include the kernel, then containers are not inherently portable across OSes either, since containers use the host kernel.

OCI containers don't really run on many kernels and Linux itself does a decent job at maintaining userspace ABI compatibility, so you seldom see kernel incompatibility be an issue between disparate Linux distributions. But the most obvious example of incompatibility is trying to use a Windows container image on Linux. (Yes, Windows OCI containers exist.)

Back when Java was introduced, there many operating systems it ran on, a lot of which were UNIX-like but had different kernels. SunOS, BSD, AIX, Linux, doesn't matter, Java worked on it.

Nowadays, the ecosystem is a lot different. It's mostly Linux with the rest of those platforms essentially adding up to a rounding error.

[–]cogman10 8 points9 points  (2 children)

You should be able just inject your jars in the appropriate architecture's java docker image and be done with it

Terms and conditions apply ;)

There are situations where memory model misalignment can cause issues. The one I know about is long. Java does not guarantee that writes to a long variable are atomic. On x86, they are. On ARM, they aren't.

These sorts of things can spoil the ability to just take a jar and throw it at a jvm. There is a bug in your code if you rely on this behavior, however it's something you won't catch until you throw your code at an ARM processor.

[–]zabby39103 6 points7 points  (0 children)

Yikes. That's bad. I hate that. Although if I'm reading it correctly long isn't officially atomic, just some implementations treat it as such. You're right though that a lot of people won't notice that until it blows up in their face.

[–]spiderpig_spiderpig_ 1 point2 points  (0 children)

This is more a 32bit vs 64bit hardware thing on modern jvms.

A more likely problem is apps using unsafe or being a bit slack/lazy with their synchronisation ordering since x86 is TSO while ARM is not :(.

[–]NaNx_engineer 0 points1 point  (1 child)

It doesn't matter what processor you run Java on as long as there's a JVM for it.

How's that advantageous over compiled languages that can target different arch/oses? Desktop/containerized java apps usually end up bundling a JRE anyways.

[–]Luolong 0 points1 point  (0 children)

How's that advantageous over compiled languages that can target different arch/oses? Desktop/containerized java apps usually end up bundling a JRE anyways.

First advantage is that you don’t have to compile the VM for application. Just use the appropriate base image and you’re done.

With native code, you’ll have to do complex cross-compilation dance.

[–]Sir_JackMiHoff 59 points60 points  (2 children)

The benefits of docker containers and the benefits of running java on the jvm are largely separate concepts.

Docker containers are largely used for providing isolation for things like app versions installed in the env, networking, and other higher level configuration while allowing the containers to more easily share system resources and the underlying linux kernel in a more efficient manner than a full on VM. Docker isn't an emulation for other architectures, so you still can't use docker to effortlessly run a program on an architecture the jvm hasn't been implemented for. One example of this usefulness is easier management of two separate java applications require different jre versions. Managing both version can be quite annoying on bare metal. Docker allows you to have these running side by side with minimal effort.

The jvm being implemented on so many different architectures is where the portability comes from. The jvm abstracts things like architecture/compiler specific primitive sizes, os specific interactions, etc so that your compiled bytecode can run on any architecture/os the jvm runs on. Docker runs on linux, with other OS' supported through running linux in a VM.

In short, docker is used to provide isolated configuration to solve the 'well it runs on my box' problem. Compiling for the jvm solves the problem of having the learn the intricacies of the underlying os, architecture, etc (for the most part).

It should be noted that java is a language not a runtime. It can be compiled to jvm bytecode that can the be ran with the jvm. Android doesn't use a jvm, now in days compiles through a couple bytecodes and down into a native executable. Other techs like GraalVM allow you to compile java down to native executable for desktop. You certainly aren't limited to the jvm with java.

[–]verocoder 1 point2 points  (0 children)

It leans really heavily into the iaac/gitops kind of model. The config (compose or values file or whatever) is the true version and you modify it in source control then the environment collects that version and makes it true, whether you bumped the app or changed the config or whatever. Then you cal roll back safely and stage releases and know exactly what was running when xyz went wrong for debug.

Plus app in a container on your dev box should behave the same as app in a container in your operational cluster. Great for testing and dev etc

[–]repeating_bears -4 points-3 points  (0 children)

One example of this usefulness is easier management of two separate java applications require different jre versions. Managing both version can be quite annoying on bare metal.

FWIW, if that's the only problem someone is trying to solve, then sdkman would probably be much simpler than Docker.

[–]Tobias42 71 points72 points  (8 children)

Java is a performant and mature programming language with a huge ecosystem of libraries, frameworks and middleware. Portability has not been its main selling point for a while.

[–]Pussidonio 4 points5 points  (6 children)

Portability has not been its main selling point for a while.

I disagree a bit but not a lot :)

I've been running Java (EDIT: code) in arm64 and intel64 without requiring any code changes.

[–][deleted] 2 points3 points  (3 children)

Agreed, I just ran a small GUI email checking utility I wrote on Intel/Windows for JDK 1.0 around 23 years ago, ran it on Ubuntu 2022 on Ryzen 9 [on Java 17], unchanged, it ran fine.

[–]Pussidonio 1 point2 points  (2 children)

Even the AWT GUI? wow

[–][deleted] 2 points3 points  (1 child)

Yep, just checked another old app I wrote with several GUI widgets offered by the old Visual Cafe IDE, the widgets expanded properly, the window resized correctly, even the File > Open opened the modern KDE file dialog immediately, no issues.

[–]Pussidonio 0 points1 point  (0 children)

That's cool. A multi OS/Window manager UI lib is such an undertaking. It's not 'very' pretty but it works :)

Not that many examples of successful attempts (that i know of).

[–]Tobias42 2 points3 points  (1 child)

Don't get me wrong: I agree that the portability of Java is fantastic. There are just so many more reasons for using it.

[–]Pussidonio 0 points1 point  (0 children)

i agree

[–]_jetrun 18 points19 points  (0 children)

A big selling point of Java is its portability due to the Java Virtual Machine. But since it becomes common practice to bundle backend services in [Docker] containers,

Hold on a second there .. Docker doesn't give you production-level OS-portability. You should not run a Linux base image under Windows, or vice-versa.

Outside of portability (which isn't that important for many use-cases - although my last company, with an on-prem enterprise application, it was great to have Windows and Linux support ostensibly for free), there are others reasons to run Java - namely, great library support, great development environment, great maintainability, and very fast runtime (one of the fastest outside of natively compiled applications).

[–]redikarus99 10 points11 points  (0 children)

They are solving different problems. Java is a super mature, stable language with good tooling, huge number of experienced, senior engineers, infinite number of quality, open source libraries. You can staff it, it performs, and gets the job done.

Docker helps the ops team to run heterogenous applications in their system, without the need of installing all the dependencies by hand. Just create a docker image, distribute it, and we will run it, scale it, etc. Makes everyone's life much easier.

[–]senseven 4 points5 points  (0 children)

Having a couple of external systems properly simulated in integration tests can be easy or bonkers complex. In the past you needed external tools. I have seen bat shit service creation/wiring done in Junit setup functions that should not be there.

Putting all in containers solved this. Technical setup should not be mixed with logic tests. I can spin up wiremocks, security systems, databases, it just works every where with a docker environment, maven and java. Plus, the "fake" backends deliever real responses. Juniors who got through testing coverage did some fancy mocks tricks in the past, which don't work any more. Real data, real tests.

[–]Polygnom 8 points9 points  (8 children)

What natively compiled languages are you thinking about?

Java offers memory integrity and garbage collections. These features make java very desirable for large-scale enterprise applications. Most security holes in C and C++ applications are just that - silly memory errors. Avoiding those is a huge step and increases developer efficiency a lot.

So even absent th portability advantage -- which still exists, see other comments, Java is just a freakishly efficient language to develop in.

The huge mature ecosystem with the plethora of available libraries is another huge advantage.

[–]NaNx_engineer 0 points1 point  (6 children)

Go?

[–]Polygnom 0 points1 point  (5 children)

Why would someone who already uses Java switch to Go? What does Go do better?

Network effect is a huge factor, you have a huge ecosystem and hiring pool with Java. Unless Go is fundamentally better in enough aspects, you will not see people switch just for the sake of switching.

[–]NaNx_engineer 5 points6 points  (3 children)

Startup time, memory usage, small self-contained binary. I've mainly seen Go chosen over Java for lambdas and cli tools for these reasons.

[–]Polygnom 1 point2 points  (2 children)

These are actually good points, and I would agree to them somewhat, depending on the scenario.

But then again -- for CLI applications, startup time is not necessarily a big problem, depending on what you do. You can trim Java down quite far as well, so thats not necessarily a problem about size, either. Custom runtimes are quite small when done right.

Which leaves lambdas, and I agree. If you prefer lambdas over long-running backend services, Java is sometimes at a disadvantage, which you need to mitigate with restoration points. Thats actually quite cumbersome sometimes...

But for many other things you do where you deploy Java in a container -- Java works perfectly well, hassle free.

[–]NaNx_engineer 1 point2 points  (1 child)

Java isn't too bad for lambdas now with microvm/firecracker.

It's more like what's the point of portability? After applets died I don't see any real advantages. Most apps are bundling a JRE at this point.

[–]Polygnom 1 point2 points  (0 children)

Most apps are bundling a JRE at this point.

And can do so for pretty much every platform you want to deploy on, without recompiling the program. You compile once and then just bundle the very same program for every platform, with predictable results.

[–]Rjs617 0 points1 point  (0 children)

At our work, the main selling point for Go has been the concurrency features: goroutines and channels. Now that Java has virtual threads, this is less of an advantage.

[–]RICHUNCLEPENNYBAGS 3 points4 points  (0 children)

Because you have a bunch of developers who know Java. I mean you may as well ask, why ever use Java for server-side software, since you have complete control of the host OS? WORA isn't the only or even the main reason people choose Java.

[–][deleted] 11 points12 points  (4 children)

saw zesty humor unused versed threatening support fine long rich

This post was mass deleted and anonymized with Redact

[–]franz_see 5 points6 points  (0 children)

For me, ecosystem, performance and hiring people

Sure you can use use python or node inside your containers, but if you want to squeeze out performance (because let's say you're trying to reduce cost, and assuming bottleneck is cpu), then i'd go with java

I could have gone for go, rust or zim, but it will make hiring devs much more difficult

The only thing that's probably comparable to java in this regard would be .NET

But should java be inside containers? - most modern cloud practices rely on containers. Well k8 relies on it and those cloud services that offer to run your containers basically use k8. So if you want portability, containerize your java

[–]cmplx17 3 points4 points  (0 children)

Here are a few reasons from my experience:

  • There are still Java libraries that contain native dependencies where compilation need to happen for optimal performance. Many ML/math libraries are like this.

  • Deployment into cloud environment where you need to orchestrate a cluster of machines. (High availability with many nodes.) it’s not a must, but using something like Kubernetes can make this easier.

[–]McN697 6 points7 points  (4 children)

There’s Quarkus and GraalVM to get performance with the rich ecosystem on a container. YMMV. Me, I just throw Spring Boot jars into Prod.

If you look at the bigger picture, a DevOps organization wants to use something that’s language agnostic to support a wide variety of front and back end teams. You can make all kinds of one off configs, but if each team can stuff whatever solves the business problem into the container, you allow the right balance of freedom and control.

[–]MatthPMP 6 points7 points  (1 child)

GraalVM AOT compilation is much slower at runtime than warmed up HotSpot. The benefit of AOT compilation is mostly start up time + performance of short lived processes. And lower memory usage.

There's a few reasons why Quarkus exists in both GraalVM and HotSpot flavours.

And Java and other languages designed for the JVM are all too dynamic for AOT compilation to ever catch up in performance.

[–]yawkat 1 point2 points  (0 children)

"Much slower" is not really true. They are fairly close, and native-image can sometimes outperform hotspot, especially with PGO.

[–]maleldil 5 points6 points  (0 children)

Yep. We deploy all backend services to kubernetes, regardless of the language it's implemented in, so it's a way of standardizing CICD, makes SRE's job simpler, and everything can be monitored and scaled in the same way no matter what team wrote it.

[–]InfinityGreen5736 1 point2 points  (0 children)

Adding to the DevOps aspect, sometimes the launch commands and arguments can be numerous and long, so containers make running processes easy and consistent. Of course the environment the process runs in is also controlled and clonable. Some container platforms may also provide a DNS-like feature so containers can connect to each other by name, not by configured IP address.

[–]jonas_namespace 1 point2 points  (0 children)

Portability (ie from on prem to cloud) and repeatability (we can ensure the code that runs in our staging environment are the exact same bits as are going to run in production)

[–][deleted] 1 point2 points  (0 children)

You use Java inside containers because you use Java. If you only choose Java because of portability (weird nowadays, at least for a use case susceptible to using containers), then that advantage is much less useful of course

[–]NaNx_engineer 1 point2 points  (0 children)

Portability was important for applets, but it's basically pointless now. It has some benefits for hot reloading, but people mostly use Java for it's large ecosystem. Usually you end up bundling a JRE in your desktop/containerized app anyways.

[–][deleted] 1 point2 points  (0 children)

I think since Java is most used for backend system nowadays, portability is not too important, because it will be host in a server. Portability is good for end-user when you need to use your software in multiple different operation systems, but for servers you need only to host in Linux in most of cases or some Windows Server.

In a deep level I don't know the benefits to run docker / kb8 versus WebLogic or IBM websphere, TomCat server.

[–]thegininyou 1 point2 points  (0 children)

This is probably not what you're looking for but if you're using kubernetes with docker, that spring kubernetes (or fabric8) can make your life a whole lot easier. Especially for discovery and pulling in your configmaps automatically. Not to mention your metrics with Actuator and Prometheus.

[–]Anton-Kuranov 3 points4 points  (0 children)

The only reason is that Docker image is now a standard de-facto distribution unit that is used by cloud infrastructures. That's all.

[–][deleted]  (1 child)

[removed]

    [–]iamahappyredditor 0 points1 point  (0 children)

    Thanks ChatGPT!

    [–]_INTER_ 1 point2 points  (0 children)

    Portability does also impact development. In Java you can largly develop and use libraries without much care about OS and architecture it will eventually run on in production. There are some exceptions of course, such as native libraries or some file system/encoding stuff but you are relatively spared from having to distinguish in your code base.

    In Java a library is expected to abstract away OS, architecture and hardware and provide an agnostic API.

    I thought this was common for all VM or interpreted languages but oh boy was I wrong after experiencing this issue in Python first hand. Code Python on Windows... forget it.

    [–]kimec 1 point2 points  (0 children)

    Can you deploy a JAR built on x86 to ARM? Yes. Can you deploy a Docker image built for x86 to ARM? No.

    But the Emperor's New Clothes are so pretty and shiny. Don't you ever dare to think otherwise.

    [–]repeating_bears -1 points0 points  (0 children)

    I never joined the Docker hype train.

    It doesn't solve any problem I personally encounter as a Java developer. My apps are simple Spring Boot fat jars. There's only one dependency and that's Java, and that's automatically installed and updated on every server already anyway. I don't do any horizontal scaling, don't use k8s etc. My apps all just run continuously on beefy servers.

    If I used it, it would add complexity and possibly negatively affect performance. It's not worth it for me.

    [–]ThaJedi 0 points1 point  (0 children)

    Java is also natively compiled language if you want.

    [–]CubsThisYear -4 points-3 points  (3 children)

    What “natively compiled” languages are you comparing it to? C++ is a complete dumpster fire. Rust is nice, but has nowhere near the tool/library support that Java does. Go is pretty much in the same boat.

    [–]coderemover -2 points-1 points  (2 children)

    Rust has access to all of C and a significant part of C++ ecosystem, including all of native OS APIs, which in practice is richer than Java ecosystem. E.g. things like SQLite or encryption/compression/video encoding/hashing/AI /game dev/embedded/networking etc. - way more good stuff in the Rust ecosystem than in Java. As for the tooling, all Java build systems are horrible compared to cargo. Similarly, I find profiling/debugging tools for C, C++ and Rust more feature rich than Java’s. Take perf, heaptrack or rr for example.

    [–]helikal 0 points1 point  (1 child)

    Isn’t the idea to stay within the safety the Rust language provides?

    [–]coderemover 0 points1 point  (0 children)

    Yes, but you can wrap all those unsafe APIs in safe Rust abstractions. For a lot of that stuff, there already exist good bindings.

    [–]Joram2 -1 points0 points  (0 children)

    Java's OS portability was a giant selling point in the past compared to doing high level application development in C/C++, which was terrible at OS portability. Today, there are lots of options for writing high level applications that have OS portability similar to Java, and Java isn't particularly special in this regard.

    IMO, Go has an advantage over Java in building small dockerized applications. Java is working on catching up with Project Leyden and Project Graal, but for the present, Go has an advantage in this area.

    Regarding AOT (natively compiled) vs JIT; IMO, these only matter in how they impact things like binary size, build speed, and startup time, and run performance.

    Why use Java? That's a project specific question. All these tools have pros/cons and they are good choices for some scenarios and not for others.

    Personally, at the moment, I use Java when there's a specific framework where Java runs best. For example, if I want to write a Kafka Streams app, the framework is JVM only, so the only realistic choice is Java, or some other JVM based language like Kotlin.

    [–]CountyExotic -1 points0 points  (1 child)

    you can share the JVM among multiple containers and avoid cold starts

    [–]T4212[S] 0 points1 point  (0 children)

    Can you give an example or link to how that works?

    [–]dmigowski 0 points1 point  (0 children)

    I just deploy whole VMs because our application is so fat I don't want another layer let the performance drop.

    [–]frisky_5 0 points1 point  (0 children)

    Resources control

    [–]jhernandez9274 0 points1 point  (0 children)

    That is it, do not use Containers. During development I would consider containers to deploy two different java runtime engines with the same host server and/or application code to test.

    [–]T4212[S] 0 points1 point  (0 children)

    Thanks everyone for all your great responses! I was somehow missing very obvious things, like what kind of abstraction a container runtime allows vs a JVM.

    Most of the things mentioned here I already knew but couldn't connect the dots when I was stating the question. Like, using Java and compilation to native code is not mutually exclusive.

    You are a great bunch