Category: Phát triển phần mềm

  • GIỚI THIỆU VỀ JAVA

    Bài này được viết với mục đích giới thiệu về Java, một trong những nền tảng và ngôn ngữ phổ biến nhất.

    Cái tên Java chỉ đến 3 phần khác nhau: ngôn ngữ Java (Java language), Java runtime và các thư viện Java. Gom chung cả 3 cái lại, ta gọi nó là Java platform.

    👉 Ngôn ngữ Java được tạo ra với cú pháp tương tự C/C++/C#, những người đã thành thạo các ngôn ngữ này có thể chuyển sang học ngôn ngữ Java trong vòng 2 nốt nhạc. Việc học gần như chỉ là so sánh xem có gì giống và khác, như các kiểu dữ liệu, các cấu trúc điều khiển, hỗ trợ OOP… Sẽ không có gì ngạc nhiên nếu một người giỏi C# chỉ sau 1 ngày có thể tham gia vào dự án Java.Tương tự các ngôn ngữ khác, Java cũng có nhiều phiên bản khác nhau, và thể hiện qua các bản đặc tả (https://docs.oracle.com/javase/specs/).

    Thành phần thứ hai là Java runtime, tức tất cả những gì để chương trình Java thực thi, đây là phần phức tạp, và mất rất nhiều thời gian để làm chủ. Để hiểu sâu được, bạn cần hiểu những thứ bên dưới giúp chương trình thực thi: quản lý bộ nhớ, class loader, mã bytecode, bộ dọn rác, JIT… Nếu ai học Java chắc hẳn đã từng gặp lỗi Class Not Found khi chạy chương trình, và cũng loay hoay không biết vì sao code mình dịch xong mà khi chạy nó cứ báo không tìm thấy. Muốn xử lý được, bạn sẽ cần biết cách Java runtime tìm các file class: các thư mục, và thứ tự nó sẽ tìm kiếm.Các trình runtime cũng sẽ có các bản đặc tả của nó, trong bản đặc tả đó người ta sẽ mô tả các tính năng nó hỗ trợ, bạn có thể xem trong đường link phía trên.

    Thành phần thứ ba là lớn nhất và mất thời gian học nhất: các thư viện Java. Các thư viện được cung cấp sẵn rất lớn, và hầu như chúng ta chỉ bắt đầu với những thứ cơ bản: io, xml, util, swing, awt, net… các phần còn lại sẽ chỉ cần học khi nào cần tới.

    (more…)
  • NÊN SỬ DỤNG MULTI THREADING THẾ NÀO

    Sau khi đã biết cách viết chương trình multi-thread, giờ ta sẽ cùng bàn đến vấn đề quan trọng hơn: Khi nào nên dùng MT, và còn có lựa chọn nào khác nữa không?

    ℹ️ Multi threading phù hợp với những trường hợp sau đây:

    👉 Chương trình cần tính toán nhiều (sử dụng nhiều năng lực tính toán của CPU) và muốn tận dụng nhiều CPU hoặc core khác nhau, mỗi thread sẽ tính toán một bài toán riêng lẻ. Tuy nhiên lưu ý là không phải cứ tạo thread mới thì nó sẽ tận dụng được các nhân khác, nếu bạn có 2 thread nhưng được gán cho cùng một core/cpu thì hiệu năng cũng sẽ không tăng lên. Với các bài toán này, bạn nên tìm hiểu về các thư viện hỗ trợ lập trình song song trên nền tảng của bạn.Ngay cả khi bạn chỉ có một bài toán cần tính, bạn cũng nên đưa vào một thread chạy ngầm bởi 2 lý do:

    – Chương trình sẽ không bị khóa cứng lại và trở nên “not responsive”, người dùng có thể theo dõi tiến độ, hoặc hủy nếu quá trình tính toán quá lâu.

    (more…)
  • Hôm trước đọc code linux có đoạn này, các bạn có thể giải thích if (!*–p) nghĩa là gì không?

    Nó sẽ là:

    p–; // chuyển đến địa chỉ trước đó (địa chỉ sẽ trừ đi size của kiểu mà p trỏ đến).

    x = *p;

    if (x == 0) {…}

  • VẤN ĐỀ ĐỒNG BỘ TRUY CẬP DỮ LIỆU

    Bài toán đồng bộ

    Đối với các chương trình single-thread, ta không cần quan tâm đến việc đồng bộ, bởi chương trình sẽ thực thi theo thứ tự từ trên xuống dưới từng câu lệnh một, trạng thái của chương trình sẽ chỉ bị thay đổi bởi chính nó. Tuy nhiên với các chương trình multi-thread, sẽ xảy ra trường hợp có nhiều hơn một thread cố gắng truy cập vào cùng một biến và gây ra sai sót.

    👉 Xét ví dụ sau khi tráo đổi giá trị hai biến x và y (swap):

    x = 10;
    y = 20;
    t = x; 
    x = y; (*)
    y = t;

    Tại vị trí (*), giá trị của x và y bằng nhau, và bằng 20. Đây có thể coi là một trạng thái sai, bởi chỉ có thể x = 10, y = 20 hoặc x = 20, y = 10 sau khi tráo đổi xong. Trước hay sau khi tráo lại thì x * y cũng phải bằng 200, tuy nhiên tại vị trí (*), x * y sẽ là 400.Nếu có một thread thứ hai đọc giá trị của x và y để xử lý công việc, sẽ có một lúc nào đó giá trị nó đọc được sẽ bị sai.Cũng với ví dụ trên, giả sử có 2 thread cùng thực thi, bởi các câu lệnh có thể ngắt quãng và thực thi xen kẽ bởi các thead khác nhau, nên có thể xảy ra trường hợp sau:(thread 1 ký hiệu t1, thread 2 ký hiệu t2)

    (more…)
  • BÀN VỀ FUNCTIONAL PROGRAMMING VÀ OOP PROGRAMMING – bài 1

    Cách đây mấy hôm tôi có đưa ra một khảo sát xem mọi người sẽ theo hướng FP hay OOP, vì hay gặp cảnh tranh cãi giữa hai trường phái này. Và thường các cuộc tranh cãi đều không có hồi kết, đơn giản vì ai cũng có lý lẽ của mình, và quan trọng nhất là không có ai có thể đưa ra được những lý do xác đáng để bên kia tin theo.

    Trong bài này tôi sẽ mặc nhiên coi các bạn đã hiểu về OOP, và sẽ nói một chút về FP (vì trong blog này chưa có bài nào nói về nó). Nếu như bạn chưa thực sự biết rõ cả OOP lẫn FP thì tất cả những lý lẽ đưa ra sẽ đều là cảm tính, do đó quan điểm đưa ra sẽ dễ trở nên phiến diện và không thuyết phục.

    Nhớ tìm đọc lại các bài OOP nếu bạn vẫn chưa nắm rõ nhé ❤️.

    ℹ️ Vậy Functional Programming là gì?

    (more…)
  • NÓI THÊM MỘT CHÚT VỀ THREAD

    Trong các ứng dụng single thread, ta chỉ có duy nhất một thread chạy trong một không gian địa chỉ (1), do vậy ta có thể đảm bảo không ai thay đổi dữ liệu trong suốt quá trình chạy. Tuy nhiên trong các ứng dụng multi-thread sẽ có 2 hoặc nhiều hơn thread chạy đồng thời và chia sẻ chung không gian địa chỉ, do vậy một trong những bài toán quan trọng nhất là đồng bộ dữ liệu dùng chung giữa các thread.

    Nên lưu ý khái niệm chạy đồng thời ở đây là tương đối, vì một máy tính có thể chỉ có rất ít CPU, nên nó phải chia sẻ giữa nhiều thread khác nhau. Trong thực tế, số thread luôn lớn hơn số CPU có trong hệ thống, trong một thời điểm có vài trăm đến vài ngàn thread chạy đồng thời là điều bình thường, mỗi thread sẽ chỉ được cấp một khoảng thời gian để chạy (gọi là time slide), sau đó HĐH sẽ lấy lại quyền điều khiển và chuyển sang thread khác.

    (more…)
  • THREAD POOL

    Khi mới học viết các ứng dụng multi thread, mỗi khi cần xử lý một công việc song song, ta thường làm theo cách sau:

    – Tạo một thread mới.

    – Truyền tham số khởi tạo và cho thread chạy để xử lý công việc.

    – Kết thúc thread và nhận kết quả.

    Một trong những bài toán phổ biến nhất cho người mới bắt đầu là viết ứng dụng chat(*). Và cách làm cũng tương tự như trên:

    – Mở server socket và listen trên server socket đó.

    – Mỗi khi có một client kết nối mới, bạn sẽ tạo một thread để chờ dữ liệu trên kết nối đó, nếu có thì xử lý, hoặc gửi dữ liệu cho đầu bên kia thông qua socket.

    – Khi hai bên hoàn thành công việc, ngắt kết nối và kết thúc thread.

    👉 Cách làm này khá đơn giản, nhưng có một số nhược điểm như sau:

    (more…)
  • LẬP TRÌNH MULTI THREAD

    Vậy là ta đã xong OOP, con trỏ và các phần nói về quản lý bộ nhớ, giờ tiếp đến một chủ đề nữa: lập trình đa luồng – multi thread programming.Trong bài này tôi chỉ giới thiệu qua các khái niệm cơ bản và các từ chuyên ngành liên quan, để dễ nhất các bạn nên đọc lại những bài viết về chủ đề quản lý bộ nhớ (stack, heap) và bài về từ khóa virtual trong OOP.

    ℹ️ Trước tiên ta cần hiểu thread là gì

    Về kỹ thuật, một thread là một chuỗi các lệnh cần được thực thi bởi CPU, hay ta có thể tưởng tượng một thread là một function, trong đó chứa các lệnh thực thi, và quan trọng nhất – nó sẽ chạy ĐỒNG THỜI với chương trình chính.Bạn có thể thấy, chương trình sẽ bắt đầu bằng hàm main, Main, hay với nhiều ngôn ngữ là từ câu lệnh đầu tiên. Mỗi khi bạn gọi một function, bạn sẽ phải chờ nó kết thúc, giờ mỗi khi gọi một hàm, nó sẽ được thực thi bởi một CPU khác, vì ta có 2 CPU nên hàm chính và hàm được gọi sẽ chạy đồng thời với nhau.

    ❓Bạn sẽ đặt câu hỏi: Nếu máy của tôi chỉ có 1 CPU, vậy làm sao tôi có thể chạy đa luồng được?

    ℹ️ Đó là nhiệm vụ của hệ điều hành, với các hệ điều hành đa nhiệm (multi tasking OS), nó sẽ có những cách sau để cho phép bạn chạy 2 thread cùng lúc.

    (more…)
  • NÓI THÊM VỀ BÀI “BỘ NHỚ STACK LÀ GÌ?”

    Giải thích về ghi chú 2: Trong hình minh họa ta sẽ thấy Stack nằm lộn ngược từ trên xuống, đó cũng là cách bộ nhớ Stack được tổ chức trong thực tế, nhờ phát triển từ địa chỉ cao xuống địa chỉ thấp mà CPU có thể phát hiện ra lỗi Stack overflow một cách dễ dàng (so sánh với 0).

    (more…)
  • BỘ NHỚ HEAP LÀ GÌ?

    Khi học về con trỏ, bạn sẽ thường xuyên phải xin cấp phát và giải phóng bộ nhớ, vậy những vùng nhớ này được quản lý bởi ai và như thế nào?

    Về cơ bản, khi khởi động lên, hệ điều hành sẽ nắm quyền kiểm soát toàn bộ bộ nhớ, bởi bộ nhớ có thể coi như một sân chơi chung nên phải có phải có người cầm trịch, quản lý xem chỗ nào đã có người dùng, chỗ nào còn trống, tránh việc dữ liệu của một chương trình này bị ghi đè bởi một chương trình khác.Khi bạn gọi hàm malloc, hoặc new, trình quản lý bộ nhớ sẽ tìm xem chỗ nào chưa có ai sử dụng, nó lấy một phần vừa đủ với kích thước bạn xin cấp phát, đánh dấu vùng nhớ đó đã được cấp cho chương trình (process) của bạn và trả về địa chỉ. Nhiệm vụ của bạn là lưu lại địa chỉ (vào một biến con trỏ) và chỉ sử dụng trong phạm vi đã được cấp.Khi bạn yêu cầu delete, trình quản lý bộ nhớ sẽ gỡ bỏ đánh dấu. Lúc này nếu tiếp tục sử dụng, chương trình của bạn có thể bị lỗi truy cập vùng nhớ không được phép và bị kết thúc.

    ℹ️ Tất cả các thao tác xin cấp phát và giải phóng này đều làm việc trên một vùng nhớ gọi là HEAP. Ta hiểu đơn giản heap là vùng nhớ còn lại sau khi đã trừ đi các phần khác của chương trình như code, dữ liệu tĩnh, stack…Việc cấp phát/sử dụng/giải phóng một vùng nhớ luôn phải làm cẩn thận vì:

    (more…)