Trong lập trình đa luồng, synchronized
là một trong những công cụ quan trọng để điều phối truy cập đến các tài nguyên chia sẻ, nhằm đảm bảo rằng không có hai luồng nào có thể truy cập cùng một tài nguyên tại cùng một thời điểm. Từ khóa synchronized
cung cấp một cơ chế để đồng bộ hóa các luồng trong Java, giúp tránh các vấn đề như điều kiện đua (race conditions) và bảo đảm tính nhất quán của dữ liệu. Bài viết này sẽ trình bày chi tiết về synchronized
, cách sử dụng, cùng với ví dụ minh họa và một số lưu ý khi làm việc với nó.
Từ khóa synchronized
trong Java được sử dụng để chỉ định rằng một phương thức hoặc một khối mã chỉ có thể được thực hiện bởi một luồng tại một thời điểm nhất định. Khi một luồng gọi một phương thức hoặc khối mã được đánh dấu là synchronized
, nó sẽ chiếm quyền sở hữu của một khóa (lock). Khi đó, các luồng khác không thể truy cập vào phương thức hoặc khối mã đó cho đến khi luồng đang sở hữu khóa hoàn tất.
Khi một luồng gọi một phương thức hoặc khối mã được đánh dấu là synchronized
, nó sẽ làm như sau:
Phương thức được khai báo là synchronized
sẽ chiếm khóa của đối tượng mà nó thuộc về:
public class Counter { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; } }
Trong ví dụ trên, phương thức increment()
và getCount()
được khai báo là synchronized
, đảm bảo rằng chỉ có một luồng có thể thực hiện chúng tại một thời điểm.
Đối với trường hợp bạn chỉ cần đồng bộ hóa một phần của mã, bạn có thể sử dụng synchronized
block:
public class Counter { private int count = 0; public void increment() { synchronized (this) { count++; } } public int getCount() { synchronized (this) { return count; } } }
Ở đây, chỉ có phần mã bên trong khối synchronized
mới được đồng bộ hóa, cho phép tăng tính linh hoạt và giảm thiểu độ trễ.
Bạn cũng có thể đồng bộ hóa một phương thức tĩnh, trong trường hợp này, khóa sẽ thuộc về lớp thay vì một thể hiện cụ thể:
public class Counter { private static int count = 0; public static synchronized void increment() { count++; } public static synchronized int getCount() { return count; } }
Dưới đây là một ví dụ hoàn chỉnh về việc sử dụng synchronized
trong một ứng dụng đa luồng:
public class SynchronizedExample { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; } public static void main(String[] args) { SynchronizedExample example = new SynchronizedExample(); Thread thread1 = new Thread(() -> { for (int i = 0; i < 1000; i++) { example.increment(); } }); Thread thread2 = new Thread(() -> { for (int i = 0; i < 1000; i++) { example.increment(); } }); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Final count: " + example.getCount()); } }
Trong ví dụ này, hai luồng cùng nhau gọi phương thức increment()
trên cùng một đối tượng SynchronizedExample
. Do phương thức được đánh dấu là synchronized
, giá trị của biến count
sẽ được cập nhật một cách an toàn mà không xảy ra tình trạng đua.
synchronized
sẽ giúp tăng hiệu suất.Từ khóa synchronized
trong Java là một công cụ quan trọng để đảm bảo tính đồng bộ giữa các luồng khi truy cập tài nguyên chia sẻ. Nó giúp tránh tình trạng đua và đảm bảo rằng dữ liệu luôn nhất quán. Tuy nhiên, việc sử dụng synchronized
cần phải được thực hiện cẩn thận để tránh ảnh hưởng tiêu cực đến hiệu suất và khả năng mở rộng của ứng dụng.