Việc đồng bộ hóa thread là một trong những yếu tố quan trọng trong lập trình đa luồng, đặc biệt trong Java. Một monitor là một cơ chế cho phép chỉ một thread có thể truy cập vào một phần mã nào đó tại một thời điểm. Trong bài viết này, chúng ta sẽ khám phá cách thức hoạt động của việc đồng bộ hóa bên trong một monitor, cùng với các khái niệm, cách sử dụng và ví dụ minh họa.

1. Monitor là gì?

1.1. Định nghĩa

Monitor là một cấu trúc dữ liệu được sử dụng để kiểm soát truy cập vào tài nguyên chia sẻ. Trong Java, mọi đối tượng đều có thể được coi là một monitor, và chúng sử dụng đồng bộ hóa để đảm bảo rằng chỉ một thread có thể truy cập vào một khối mã nhất định tại một thời điểm.

1.2. Tính chất

Monitor có hai tính chất chính:

  • Mutual Exclusion: Chỉ một thread có thể thực thi một phần mã bên trong monitor tại một thời điểm.
  • Wait: Nếu một thread đang nắm giữ monitor và một thread khác cố gắng truy cập vào monitor đó, thread thứ hai sẽ phải chờ cho đến khi monitor trở nên khả dụng.

2. Cách thức hoạt động của việc đồng bộ hóa trong monitor

2.1. Synchronized Keyword

Trong Java, việc đồng bộ hóa thread bên trong monitor được thực hiện bằng cách sử dụng từ khóa synchronized. Khi một thread muốn truy cập vào một phương thức hoặc một khối mã đồng bộ, nó phải “chiếm giữ” monitor của đối tượng đó.

2.1.1. Đồng bộ hóa phương thức

Khi sử dụng từ khóa synchronized trên một phương thức, toàn bộ phương thức sẽ trở thành một khối mã đồng bộ:

public synchronized void synchronizedMethod() {
    // Khối mã được đồng bộ hóa
}

2.1.2. Đồng bộ hóa khối mã

Ngoài việc đồng bộ hóa toàn bộ phương thức, bạn cũng có thể đồng bộ hóa một phần của mã bằng cách sử dụng từ khóa synchronized trong khối mã:

public void method() {
    synchronized (this) {
        // Khối mã được đồng bộ hóa
    }
}

2.2. Đối tượng monitor

Khi một thread thực hiện một phương thức hoặc khối mã được đồng bộ hóa, nó sẽ nắm giữ monitor của đối tượng tương ứng. Nếu một thread khác muốn vào khối mã đồng bộ hóa đó, nó sẽ bị chặn cho đến khi thread đầu tiên hoàn thành và giải phóng monitor.

2.3. Ví dụ minh họa

Dưới đây là một ví dụ về cách thức đồng bộ hóa hoạt động bên trong monitor:

class Counter {
    private int count = 0;

    // Phương thức đồng bộ hóa
    public synchronized void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();

        // Tạo các thread
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        });

        // Khởi động các thread
        t1.start();
        t2.start();

        // Chờ cho đến khi các thread hoàn thành
        t1.join();
        t2.join();

        // Xuất kết quả
        System.out.println("Giá trị cuối cùng của count: " + counter.getCount());
    }
}

Trong ví dụ trên:

  • Chúng ta có một lớp Counter với phương thức increment() được đồng bộ hóa.
  • Hai thread t1t2 cùng tăng giá trị của biến count lên 1000 lần mỗi thread.
  • Do increment() được đồng bộ hóa, chúng ta đảm bảo rằng chỉ một thread có thể thực hiện tăng giá trị của count tại một thời điểm.

3. Các kỹ thuật đồng bộ hóa khác

3.1. Reentrant Locks

Bên cạnh việc sử dụng từ khóa synchronized, Java cung cấp ReentrantLock, cho phép lập trình viên kiểm soát tốt hơn việc đồng bộ hóa và thực hiện các thao tác phức tạp hơn.

3.2. Các cấu trúc đồng bộ hóa khác

Java cũng cung cấp các cấu trúc đồng bộ hóa khác như CountDownLatch, CyclicBarrier, và Semaphore cho các tình huống khác nhau trong lập trình đa luồng.

4. Kết luận

Việc đồng bộ hóa thread bên trong monitor là một khía cạnh quan trọng trong lập trình đa luồng trong Java. Qua việc sử dụng từ khóa synchronized, lập trình viên có thể đảm bảo rằng các tài nguyên chia sẻ được truy cập một cách an toàn. Tuy nhiên, cần lưu ý rằng việc đồng bộ hóa không chỉ đơn giản là sử dụng từ khóa, mà còn liên quan đến việc quản lý hiệu suất và tránh tình trạng deadlock.