07-05 04:18
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 |
Tags
- Operator
- Entity Set
- 리눅스 마스터 1급
- Java
- python
- Binary Search
- 리눅스 기초
- Entity
- 셀레니움
- 백준
- preprocessing
- 자바
- Reference Type
- Physical Scheme
- BFS
- selenium
- Inheritance
- descriptive statistics
- OOP
- Unity
- X.org
- External Scheme
- Mac
- X윈도우
- Polymolphism
- 리눅스
- dbms
- Class
- literal
- systemd
Archives
- Today
- Total
Byeol Lo
Singleton 본문
하나의 클래스는 오직 하나의 인스턴스만을 생성해야 한다.
장점으로는 하나의 인스턴스를 기반으로 공유를 한다면 생성 비용도 줄며, 메모리를 공유할 수 있지만, 단점으로는 의존성이 높아지고, 테스트를 할 때 잘 설정해주어야 한다(한 인스턴스로만 하기 때문에 묶여 있어서 주의해야 함). 특히 DB를 연결한 후에 ORM 기반의 인스턴스를 하나로 운영하는 것도 singleton을 잘 활용한 예라고 할 수 있다.
이렇게 한다면 다른 모듈들이 instance 생성 이라는 프로세스를 여러번 하지 않아도 미리 연결된 instance가 있고, 생성된 instance가 있기 때문에 굳이 RAM을 더 잡아먹어서 생성할 필요가 없다는 것이다(물론 상황에 따라 다르겠지만).
밑은 그 예시다
public class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) instance = new Singleton();
}
}
return instance;
}
public void doSomething() {
System.out.println("Singleton instance is doing something.");
}
}
혹은 다음과 같이 생성할 수도 있다.
class Singleton {
private static class singleInstanceHolder {
pricate static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return singleInstanceHolder.INSTANCE;
}
}
보통은 두번째 방법을 더 선호한다.
volatile: 모든 스레드가 직접 메인 메모리에서 읽고 쓸 수 있도록 하는 접근 제한자 비슷한 것으로 보면 되지만, 원자성을 보장하지 않기 때문에 synchronized 블록이나 ReentrantLock과 같은 강력한 synchronize mechanism이 필요하다. volatile이 방지하는 것은 기계어로 번역될 때의 명령어 재배치를 일관되게만 할 뿐이다. 그래서 volatile을 사용하는 목적은 그냥 해당 변수를 다른 스레드에서 보여주기 위해, 보기 위해서 사용하는 접근 제한자이다.
synchronized: critical section 을 설정하여 여러 스레드가 동시에 접근하지 못하도록 블록을 설정한다.
java.util.concurrent: AtomicInteger, AtomicLong 등의 클래스를 사용하여 원자적 연산을 보장한다.
Lock interface, 구현체 사용: ReentrantLock과 ReadWriteLock 등을 사용하여 더 세밀한 동기화 제어를 할 수 있다.
Lock interface, impl 예시
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
// Shared resource class
class SharedResource {
private int count = 0;
private Lock lock = new ReentrantLock(); // ReentrantLock instance
public void increment() {
lock.lock(); // Acquire the lock
try {
count++; // Critical section: incrementing the shared resource
} finally {
lock.unlock(); // Release the lock
}
}
public int getCount() {
return count;
}
}
// Main class to demonstrate usage
public class ReentrantLockExample {
public static void main(String[] args) throws InterruptedException {
final int THREAD_COUNT = 5;
SharedResource sharedResource = new SharedResource();
// Create threads that increment the shared resource
Thread[] threads = new Thread[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
sharedResource.increment();
}
});
threads[i].start();
}
// Wait for all threads to complete
for (Thread thread : threads) {
thread.join();
}
// Print the final count
System.out.println("Final count: " + sharedResource.getCount());
}
}
(OS에서 더 자세히 살펴볼 수 있습니다.)
'BackEnd > Design Pattern' 카테고리의 다른 글
Factory (0) | 2024.06.30 |
---|---|
SOLID (0) | 2024.06.11 |
Comments