There are several parts where I disagree with your points;
All the programming languages must use OS Thread(s) to achieve concurrency. It's just the approach to achieve the concurrency differs.
You mentioned
Go does not create OS threads. Instead, it creates a much lighter go routines
No, you have to define a go-routine to achieve concurrency for which Go schedules the task defined inside go-routine and it will be executed inside the pre-spawned thread through the concept of Communicating Sequential Process(CSP)
Goroutine is not a new concept. Actors(Scala), Coroutines(Kotlin), for that matter, it can be introduced in Java too, through a library -- Quasar Fibers or Scala Actors (interoperated). When you see any documentation mentioning lightweight/green threads, what they actually mean is to provide concurrency through scheduling the tasks instead of spawning new threads for each task. And to manage Stack size of several isolated tasks in a single thread is difficult wrt JVM based languages, particularly Java, whereas Golang smartly called it segmented stack to dynamically grow the stack size because it directly utilises OS threads.
Now comes my primary point:
Why there is a relation established between Stack Size and Concurrency?
Let's look at the general definition of both. Stack Size is the capacity provided to store the function/procedure calls or in simple terms, the stack of line numbers of the function call hierarchy. Concurrency is the ability to perform tasks simultaneously such that idle resources are completely utilized regardless of no. of threads or CPUs. So, Stack-Size plays around the flow of the function and Concurrency plays around the flow of program-logic. The only time both meets at a point is during recursion but that's no where suffice to jump into conclusion on concurrency just because the stack-size of two languages are different.
Talking about Web Server;
I completely agree to the point that Golang handles incoming requests through go-routines but the Java neither spawns a new thread for each request nor it adds the request to the thread stack.
Earlier, Java used to have Thread-based Servers (until Servlets v4.0) where a Pool of Worker Threads are created initially and all the requests are delegated to that thread pool. This caused C10K Problem -- Handling Concurrent 10K Connections. This is where people used to Spin-up more Worker Threads in the Pool. In the recent years, the concept of Multi-threaded Event pool concept is pretty common in all the Java Web Servers like Netty, Servlets 4.1+, Jersey etc. which acts like NodeJS event loops but multiple event loops. Long gone are the days where you actually create threads.
The only places where Golang hits up is
In-case you want a benchmarks on the performance:
Having said that; I like both the languages. Java because of its stability and ecosystem and Golang because of its simplicity. Both are ridiculously performant, though IO is not Java's best suite because of blocking JDBC driver.
If anyone has different view on my comment, I'd be happy to discuss. :)
Cheers!