Chào các em, chủ đề hôm nay của anh sẽ bàn về Design Pattern là Singleton ? Khi nào chúng ta sẽ dùng nó trong lập trình.
Singleton Pattern giúp chúng ta tạo ra một đối tượng duy nhất trong hệ thống. Ví dụ như anh muốn xây dựng đối tượng cache. Thì trong toàn bộ chương trình anh chỉ có một đối tượng đó chứa các giá trị. Các modules khác trong hệ thống có thể lấy giá trị này ra. Cho dù nhiều module cùng thao tác lấy giá trị từ cache , nhưng giá trị vẫn lấy ra và cập nhật đúng vì trong cả chương trình ta chỉ có 1 đối tượng cache duy nhất. Nó được dùng để chia sẽ với các modules mà gọi nó.
public final class Singleton {
private static Singleton instance;
public String value;
private Singleton(String value) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
this.value = value;
}
public static Singleton getInstance(String value) {
if (instance == null) {
instance = new Singleton(value);
}
return instance;
}
}
Bươc 3 : tạo method getInstance trả về đối tượng Singleton static Singleton getInstance(String value)
Sử dụng Singleton bằng cách sau đây.
public class DemoSingleThread {
public static void main(String[] args) {
System.out.println("If you see the same value, then singleton was reused (yay!)" + "\n" +
"If you see different values, then 2 singletons were created (booo!!)" + "\n\n" +
"RESULT:" + "\n");
Singleton singleton = Singleton.getInstance("FOO");
Singleton anotherSingleton = Singleton.getInstance("BAR");
System.out.println(singleton.value);
System.out.println(anotherSingleton.value);
}
}
Như vậy trong toàn bộ hệ thống của chúng ta chỉ có 1 đối tượng Singleton duy nhất và lấy nó ra bằng phương thức getInstance. Ngoài ra chúng ta có thể định nghĩa một loạt các method trong class Singleton như setValue(), getValue() hoặc bất cứ phương thức nào tuỳ thích.
Có một vấn đề xảy ra ở Singleton ở trên là nếu như anh có nhiều Thread (tiến trình) cùng truy cập vào biến Singletion để lấy dữ liệu thì sẽ xảy ra xung đột. Để tránh tình trạng đó chúng ta sử dụng Threadsafe như sau
public final class Singleton {
private static volatile Singleton instance;
public String value;
private Singleton(String value) {
this.value = value;
}
public static Singleton getInstance(String value) {
Singleton result = instance;
if (result == null) {
synchronized (Singleton.class) {
result = instance;
if (result == null) {
instance = result = new Singleton(value);
}
}
}
return instance;
}
}
public class DemoMultiThread {
public static void main(String[] args) {
System.out.println("If you see the same value, then singleton was reused (yay!)" + "\n" +
"If you see different values, then 2 singletons were created (booo!!)" + "\n\n" +
"RESULT:" + "\n");
Thread threadFoo = new Thread(new ThreadFoo());
Thread threadBar = new Thread(new ThreadBar());
threadFoo.start();
threadBar.start();
}
static class ThreadFoo implements Runnable {
@Override
public void run() {
Singleton singleton = Singleton.getInstance("FOO");
System.out.println(singleton.value);
}
}
static class ThreadBar implements Runnable {
@Override
public void run() {
Singleton singleton = Singleton.getInstance("BAR");
System.out.println(singleton.value);
}
}
}