Multithreading: Java Synchronized Blocks

Java synchronized blocks (Khối xử lý đồng bộ) được sử dụng để tránh xảy ra race conditions (Điều kiện tương tranh). Nếu các bạn đã đọc qua bài viết của tôi thì các thuật ngữ trên không có gì là khó hiểu cả.

1. The Java synchronized Keyword

Synchronized blocks trong Java được thể hiện qua từ khóa synchronized. Một khối đồng bộ trong Java được đồng bộ trên các object. Tất cả các khối đồng bộ được đồng bộ trên cùng một object có thể có một thread được thực thi trong chúng trên cùng một thời điểm. Toàn bộ các thread khác khi cố gắng tham gia vào khối đồng bộ đều bị chặn lại cho tới khi thread bên trong khối xử lý không còn tồn tại.

synchronized keyword có thể được sử dụng để thể hiện cho 4 kiểu blocks khác nhau:

  • Instance methods
  • Static methods
  • Code blocks bên trong instance methods
  • Code blocks bên trong static methods

Các khối này được đồng bộ trên các đối tượng khác nhau. Tùy vào các tình hình cụ thể mà chúng ta cần các loại synchronized blocks khác nhau.

2. Synchronized Instance Methods

Dưới đây là một ví dụ về synchronized instance method:

public synchronized void add(int value){
    this.count += value;
}

Chúng ta cần sử dụng từ khóa synchronized trong việc khai báo method. Điều này cho Java hiểu rằng đây là một synchronized method.

Một synchronized instance method trong Java được đồng bộ trên instance (object) sở hữu method đó. Như vậy, mỗi instance có các synchronized method được đồng bộ trên một đối tượng khác nhau. Chỉ có một thread có thể thực hiện bên trong một instance method. Nếu có nhiều hơn một instance tồn tại, thì một thread ở một thời điểm có thể được thực thi bên trong synchronized instance method trên mỗi instance.

3. Synchronized Static Methods

Static methods có cơ chế synchronized tương tự như instance methods và cũng sử dụng từ khóa synchronized. Dưới đây là một ví dụ:

public static synchronized void add(int value){
    count += value;
}

Synchronized static methods thì được đồng bộ trên class object sở hữu các static method đó. Vì chỉ có một class object tồn tại trong máy ảo Java với mỗi Class, do đó chỉ có một thread có thể thực hiện bên trong static synchronized method trên một Class.

Nếu static synchronized methods được đặt trên các Class khác nhau thì một thread có thể được thực thi bên trong static synchronized methods của các Class đó.

4. Synchronized Blocks trong Instance Methods

Chúng ta có thể create một khối synchronize ngay bên trong method. Đôi lúc chúng ta chỉ muốn xử lý đồng bộ một phần của method.

public void add(int value){
    synchronized(this){
       this.count += value;
    }
}

Trong ví dụ này, ta sử dụng Java synchronized block construct để đánh dấu khối xử lý đồng bộ. Tuy nhiên đoạn mã trên không được thực hiện giống như một synchronized methods.

Chỉ có một thread bên trong Java code block được đồng bộ trên cùng một monitor object.

Hai ví dụ sau đây đều được đồng bộ trên một instance khi gọi ra:

public class MyClass {
    public synchronized void log1(String msg1, String msg2){
        log.writeln(msg1);
        log.writeln(msg2);
    }
    public void log2(String msg1, String msg2){
        synchronized(this){
            log.writeln(msg1);
            log.writeln(msg2);
        }
    }
}

Chỉ có một thread có thể thực thi bên trong mỗi synchronized blocks ở ví dụ trên.

5. Synchronized Blocks trong Static Methods

Tương tự, chúng ta sẽ tiếp tục xem xét ví dụ về synchronized blocks trong static methods

public class MyClass {
    public static synchronized void log1(String msg1, String msg2){
        log.writeln(msg1);
        log.writeln(msg2);
    }

    public static void log2(String msg1, String msg2){
        synchronized(MyClass.class){
            log.writeln(msg1);
            log.writeln(msg2);
        }
    }
}

6. Java Synchronized Example

Dưới đây là một ví dụ về việc cùng khởi chạy 2 threads và cùng gọi tới add method trên cùng instance của Counter. Vì các method được đồng bộ trên instance của chính nó, nên chỉ có một thread ở một thời điểm có thể gọi tới add method trên cùng một instance.

public class Counter {
    long count = 0;
    public synchronized void add(long value) {
        this.count += value;
    }
}

public class CounterThread extends Thread {

    protected Counter counter = null;

    public CounterThread(Counter counter) {
        this.counter = counter;
    }

    public void run() {
        for(int i=0; i<10; i++){
            counter.add(i);
        }
    }
}

public class Example {

    public static void main(String[] args) {
        Counter counter = new Counter();
        Thread  threadA = new CounterThread(counter);
        Thread  threadB = new CounterThread(counter);

        threadA.start();
        threadB.start();
    }
}

7. Reference


All Rights Reserved