Có rất nhiều câu trả lời về điều này, nhưng nó có thể gây nhầm lẫn. Tôi thích nghĩ về nó theo cách này, và có lẽ nó sẽ giúp?:
Lập trình đồng thời là mã không quan tâm đến thứ tự thực hiện. Java là một ngôn ngữ kém để lập trình đồng thời, nhưng có các thư viện và khung để trợ giúp. JavaScript là một ngôn ngữ tuyệt vời để lập trình đồng thời và thường rất khó khi bạn muốn viết một cái gì đó không đồng thời (ví dụ: nếu bạn muốn buộc thứ tự thực hiện). Lập trình đồng thời rất tốt cho lập trình hướng sự kiện (trong đó thứ tự thực hiện được xác định bởi người nghe sự kiện, như mã chạy trong trình duyệt của bạn hoạt động khi bạn nhấp vào nút hoặc nhập vào hộp).
Một ví dụ sẽ bao gồm việc tạo ra một trăm yêu cầu HTTP. Trong NodeJS, giải pháp đơn giản nhất là mở tất cả 100 yêu cầu cùng một lúc bằng phương thức gọi lại và khi các phản hồi quay lại, một phương thức được thực thi mỗi lần. Đó là lập trình đồng thời. Trong Ruby, giải pháp đơn giản nhất (phổ biến nhất) là mở một yêu cầu và xử lý phản hồi, mở yêu cầu tiếp theo và xử lý phản hồi, v.v. Đối với nhiều yêu cầu, NodeJS dễ dàng thực hiện một cách kịp thời, mặc dù bạn phải cẩn thận để tránh làm hỏng máy chủ hoặc tối đa hóa các kết nối ra bên ngoài của bạn (dễ làm do nhầm lẫn). Bạn có thể viết Ruby theo cách đồng thời, nhưng đó không phải là cách viết mã Ruby nhiều nhất và làm tổn thương một chút để làm điều đó.
Lập trình song songlà mã có thể được chạy đồng thời trong nhiều luồng hoặc tiến trình. Điều này cho phép bạn tối ưu hóa hiệu suất bằng cách chạy mã trên nhiều CPU (thường bao gồm nhiều máy, như bạn có thể làm với một cái gì đó như Akka). Vì NodeJS không đa luồng và không có thực thi song song, bạn không phải lo lắng về việc viết mã luồng an toàn (và hầu hết mã JavaScript tôi thấy không phải là luồng an toàn). Trong Java, mặc dù ngôn ngữ không biến lập trình đồng thời thành mẫu bình thường, lập trình song song được tích hợp rất nhiều và bạn thường phải lo lắng về an toàn luồng. Nếu bạn đang viết một trang web bằng Java, thông thường, nó sẽ được chạy trong một thùng chứa chạy từng yêu cầu trong một luồng riêng biệt trong cùng một bộ nhớ,
Một số ở trên phụ thuộc vào phạm vi và ranh giới bạn đang nói đến. Tôi làm việc trên trang web. Hầu hết các mã Java tôi thấy không phải là lập trình đồng thời. Chắc chắn, nếu bạn thu nhỏ đủ, thứ tự mà khách hàng yêu cầu đến không quan trọng, nhưng nếu bạn phóng to hơn nữa, thứ tự mà mọi thứ được thực thi sẽ được quy định bởi mã. Nhưng mã được viết để các yêu cầu có thể thực thi song song với nhiều đối tượng được chia sẻ phải an toàn cho luồng.
Trong khi đó, hầu hết các mã JavaScript tôi thấy là đồng thời: nó được viết theo cách mà thứ tự thực hiện là không quan trọng ở nhiều cấp độ. Nhưng nó không được viết để hỗ trợ thực thi song song trong bộ nhớ dùng chung. Chắc chắn, bạn có thể thực thi cùng một mã song song trên nhiều quy trình, nhưng các đối tượng không được chia sẻ, vì vậy nó không phải là lập trình song song theo bất kỳ ý nghĩa nào.
Để đọc thêm, tôi thực sự thích các hình minh họa trong câu trả lời hàng đầu cho câu hỏi này tại đây: https://www.quora.com/What-are-the-differences-b between-met-copcản-and-asynyncous-programming