На це є безліч відповідей, але це може заплутати. Мені подобається думати про це так, а може, це допомагає?
Одночасне програмування - це код, який не дбає про порядок виконання. Java є поганою мовою для одночасного програмування, але для цього є бібліотеки та рамки. JavaScript є чудовою мовою для одночасного програмування, і часто важко, коли ви хочете написати щось, що не є одночасно (наприклад, якщо ви хочете примусити порядок виконання). Одночасне програмування чудово підходить для програмування, керованого подіями (де порядок виконання визначається слухачами подій, як, наприклад, код, що працює у вашому браузері, який діє при натисканні кнопки або введенні в поле).
Наприклад, можна створити сто HTTP-запитів. У NodeJS найпростішим рішенням є відкриття всіх 100 запитів одразу методом зворотного виклику, а коли відповіді повертаються, метод виконується щоразу. Це паралельне програмування. У Ruby найпростішим (найпоширенішим) рішенням є відкриття запиту та обробка відповіді, відкриття наступного запиту та обробка відповіді тощо. Для багатьох запитів NodeJS простіше зробити своєчасно, хоча ви повинні бути обережно, щоб уникнути забивання сервера або максимізації вихідних з'єднань (це легко зробити помилково). Ви можете написати Ruby одночасно, але це не так, як написано більшість коду Ruby, і це боляче трохи це робити.
Паралельне програмуванняце код, який може запускатися одночасно в декількох потоках або процесах. Це дозволяє оптимізувати продуктивність за допомогою запуску коду в декількох процесорах (часто включаючи декілька машин, як це можливо з Akka). Оскільки NodeJS не є багатопотоковою і не має паралельного виконання, вам не доведеться турбуватися про написання коду потокової безпеки (і більшість кодів JavaScript, який я бачив, не є безпечним для потоків). У Java, навіть якщо мова не робить одночасне програмування звичайною схемою, паралельне програмування дуже вбудоване, і вам часто доводиться турбуватися про безпеку потоків. Якщо ви пишете Веб-сайт на Java, це зазвичай буде запускатися в контейнері, який виконує кожен запит в окремому потоці в одній пам'яті
Деякі з перерахованих вище залежать від сфери та меж, про які ви говорите. Я працюю на Веб-сайтах. Більшість кодів Java, які я бачу, не є одночасним програмуванням. Звичайно, якщо ви зменшите масштаб, зменшення порядку, на яке подає запит клієнта, не є важливим, але якщо ви збільшуєте масштаб далі, порядок виконання речей диктується кодом. Але код написаний так, що запити можуть виконуватися паралельно з великою кількістю спільних об'єктів, які повинні бути безпечними для потоків.
Тим часом більшість кодів JavaScript, які я бачу, є одночасними: він написаний таким чином, що порядок виконання є неважливим на багатьох рівнях. Але він не написаний для підтримки паралельного виконання у спільній пам'яті. Звичайно, ви можете виконувати один і той же код паралельно в декількох процесах, але об'єкти не поділяються, тому це не паралельне програмування в будь-якому змістовному сенсі.
Для додаткового читання мені дуже подобаються ілюстрації у верхній відповіді на це запитання тут: https://www.quora.com/What-are-the-differences-bet between-parallel-concurrent-and-asynchronous-programming