Hay muchas respuestas sobre esto, pero puede ser confuso. Me gusta pensar de esta manera, ¿y tal vez ayuda ?:
La programación concurrente es un código que no se preocupa por el orden de ejecución. Java es un lenguaje pobre para la programación concurrente, pero hay bibliotecas y marcos para ayudar. JavaScript es un lenguaje excelente para la programación concurrente, y a menudo es difícil cuando quieres escribir algo que no es concurrente (por ejemplo, si quieres forzar el orden de ejecución). La programación concurrente es excelente para la programación dirigida por eventos (donde el orden de ejecución está determinado por los oyentes de eventos, como el código que se ejecuta en su navegador que actúa cuando hace clic en un botón o escribe en un cuadro).
Un ejemplo incluiría la creación de cien solicitudes HTTP. En NodeJS, la solución más simple es abrir las 100 solicitudes a la vez con un método de devolución de llamada, y cuando vuelven las respuestas, se ejecuta un método cada vez. Esa es la programación concurrente. En Ruby, la solución más simple (más común) es abrir una solicitud y manejar la respuesta, abrir la siguiente solicitud y manejar la respuesta, etc. Para muchas solicitudes, NodeJS es más fácil de hacer de manera oportuna, aunque debe ser Tenga cuidado de no dañar el servidor o maximizar sus conexiones salientes (fácil de hacer por error). Puede escribir Ruby de manera concurrente, pero no es así como se escribe la mayoría del código Ruby, y duele un poco hacerlo.
Programación paralelaes un código que puede ejecutarse simultáneamente en múltiples hilos o procesos. Esto le permite optimizar el rendimiento ejecutando el código en múltiples CPU (a menudo, incluyendo múltiples máquinas, como lo haría con algo como Akka). Debido a que NodeJS no es multiproceso y no hay ejecución paralela, no tiene que preocuparse por escribir código seguro para subprocesos (y la mayoría del código JavaScript que he visto no es seguro para subprocesos). En Java, aunque el lenguaje no hace que la programación concurrente sea el patrón normal, la programación paralela está muy integrada y, a menudo, debe preocuparse por la seguridad de los subprocesos. Si está escribiendo un sitio web en Java, normalmente se ejecutará en un contenedor que ejecuta cada solicitud en un hilo separado en la misma memoria,
Algunos de los puntos anteriores dependen del alcance y los límites de los que está hablando. Yo trabajo en sitios web. La mayoría del código Java que veo no es programación concurrente. Claro, si se aleja lo suficiente, el orden que ingresan las solicitudes del cliente no es importante, pero si se acerca más allá de eso, el orden dicta que las cosas se ejecuten. Pero el código está escrito para que las solicitudes puedan ejecutarse en paralelo con muchos objetos compartidos que deben ser seguros para subprocesos.
Mientras tanto, la mayoría del código JavaScript que veo es concurrente: está escrito de manera que el orden de ejecución no es importante en muchos niveles. Pero no está escrito para admitir la ejecución paralela en la memoria compartida. Claro, puede ejecutar el mismo código en paralelo en múltiples procesos, pero los objetos no se comparten, por lo que no es una programación paralela en ningún sentido significativo.
Para lectura adicional, me gustan mucho las ilustraciones en la respuesta superior a esta pregunta aquí: https://www.quora.com/What-are-the-differences-between-parallel-concurrent-and-asynchronous-programming