Mụ tả:
Một mẫu Critical Section là một đoạn mó được thực thi bởi một tiến trỡnh tại một thời điểm để cho kết quả mong muốn. Khi hơn một tiến trỡnh được phộp thực thi đoạn mó này, nú cú thể sinh ra những kết quả khụng dự đoỏn được.
Số húa bởi Trung tõm Học liệu - Đại học Thỏi Nguyờn http://www.lrc-tnu.edu.vn
Ta thiết kế một lớp thụng bỏo đăng nhập FileLogger là một Singleton. Việc tiến hành phương thức getFileLogger sẽ làm việc tốt trong mụi trường đơn tiến trỡnh. Trong mụi trường đa tiến trỡnh, hai tiến trỡnh cú thể cựng thực hiện phương thức getFileLogger để kiểm tra xem biến lớp đăng nhập cú null hay khụng và qua đú khởi tạo biến đăng nhập hai lần. Cú nghĩa là phương thức khởi tạo riờng đó khởi tạo hai lần.
public class FileLogger implements Logger { private static FileLogger logger; private FileLogger() {
}
public static FileLogger getFileLogger() { if (logger == null) {
logger = new FileLogger(); }
return logger; }
public synchronized void log(String msg) { FileUtil futil = new FileUtil();
futil.writeToFile("log.txt”,msg, true, true); }
}
Việc khởi tạo biến đăng nhập hai lần trong vớ dụ này khụng gõy lỗi. Bởi vỡ constructor của FileLogger là private khụng làm gỡ phức tạp. Ngược lại, nếu phương thức khởi tạo singleton thực thi cỏc hành động như mở một cổng kết nối đặc biệt, việc khởi tạo hai lần cú thể gõy lỗi.
Chỳng ta hóy củng cố thiết kế của lớp FileLogger để làm cho nú thớch hợp với việc sử dụng trong mụi trường đa tiến trỡnh. Điều này cú thể được thực hiện theo hai cỏch.
Phương phỏp I (Critical Section)
Phương phỏp này bao gồm việc làm cho phương thức getFileLogger thành một Critical Section để chỉ một tiến trỡnh cú thể thực thi nú đỳng lỳc tại một thời điểm. Việc này được thực hiện đơn giản khai bỏo phương thức ở cấp độ lớp getFileLogger là synchronized.
public class FileLogger implements Logger { private static FileLogger logger;
Số húa bởi Trung tõm Học liệu - Đại học Thỏi Nguyờn http://www.lrc-tnu.edu.vn
private FileLogger() { }
public static synchronized FileLogger getFileLogger() { if (logger == null) {
logger = new FileLogger(); }
return logger; }
public synchronized void log(String msg) { FileUtil futil = new FileUtil();
futil.writeToFile("log.txt”,msg, true, true); }
}
Thay đổi đơn giản này chuyển phương thức getFileLogger thành Critical Section và đảm bảo rằng khụng cú hai tiến trỡnh cựng thực thi phương thức getFileLogger tại một thời điểm. Điều này sẽ xoỏ bỏ hoàn toàn khả năng hàm khởi tạo FileLogger khởi động hơn một lần bờn trong phương thức getFileLogger.
Phương phỏp II (Static Early Initialization)
Chỳ ý rằng phương thức đồng bộ cú thể cú tỏc dụng quan trọng lờn việc hoạt động của toàn ứng dụng. Núi chung, cỏc phương thức đồng bộ chạy khỏ chậm, chạy chậm gấp khoảng 100 lần so với phương thức khụng đồng bộ. Để thay thế cho việc khai bỏo phương thức getFileLogger là đồng bộ, biến đăng nhập cú thể sớm được khởi tạo.
public class FileLogger implements Logger { //Early Initialization
private static FileLogger logger = new FileLogger(); private FileLogger() { }
public static FileLogger getFileLogger() { return logger;
}
public synchronized void log(String msg) { FileUtil futil = new FileUtil();
futil.writeToFile("log.txt”,msg, true, true); }
}
Điều này loại bỏ nhu cầu kiểm tra hay khởi tạo bờn trong phương thức getFileLogger. Do vậy, phương thức getFileLogger trở thành tiến trỡnh an toàn một
Số húa bởi Trung tõm Học liệu - Đại học Thỏi Nguyờn http://www.lrc-tnu.edu.vn
cỏch tự động mà khụng phải khai bỏo nú là đồng bộ.