π κΈλ 6κΈ° ν¬μ€ν
1. λ―ΈμΉλλ‘ λμ λ 7μμ νκ³
2. μ¬μ©μκ° κ²μλ¬Όμ μμ±ν λμ νΈλμμ μ²λ¦¬
3. Spring AOP - (1) νλ‘μ ν¨ν΄, λ°μ½λ μ΄ν° ν¨ν΄
4. [MySQL] - νΈλμμ μ 격리 μμ€(Isolation level)
5. Spring AOP - (2) AOP κ°λ λ° μ€μ΅
6. μΈν 리μ μ΄(IntelliJ) - λλ²κΉ (Debugging) νκΈ°
7. [Java, λμμΈν¨ν΄] - μ±κΈν΄ ν¨ν΄(Singleton Pattern)
8. μκ° μ½λ리뷰 Ver_0.1: μ»€λ¦¬μ΄ μ±μ₯ CODE μΈλ―Έλ μ 리
9. ν¬μ€νΈλ§¨(API ν μ€νΈ) νμ©νκΈ°
π λμμΈ ν¨ν΄ - μ±κΈν΄ ν¨ν΄(Singleton Pattern)
ν¬μ€ν μμ μμ±ν μμ μ½λλ κΉνλΈμμ νμΈνμ€ μ μμ΅λλ€ :)
μλ νμΈμ, μ΄λ² μκ°μ μ 리ν λ΄μ©μ λμμΈ ν¨ν΄μμμ μ±κΈν΄ ν¨ν΄μ λλ€. κ·Έλμ λμμΈ ν¨ν΄μ μ€μμ±μ λν΄μλ μμ£Ό λ€μ΄μμμ΅λλ€. νμ§λ§ λμμΈ ν¨ν΄μ νμ΅νλλΌλ μ€μ κ°λ°μ μ§ννλ©° λμμΈ ν¨ν΄μ μ§μ μ μ©ν΄λ³΄λ μΌμ΄ μμκΈ°μ λ€μ κΉλ¨Ήκ²λλ μ μνμ΄ λ°λ³΅λμλλ°μ, μ΄λ²μ λμμΈ ν¨ν΄μ λν΄ μ²μ²ν μ 리λ₯Ό νμ¬ μμΌλ‘ κ°λ°μ μ§νν λ μ μ ν μν©μμ μ μ ν ν¨ν΄μ μ μ©ν μ μλλ‘ λ―Έλ¦¬ νμ΅νλ κ²μ λͺ©νλ‘ νκ³ μ ν©λλ€. μ΄λ¬ν λμμΈ ν¨ν΄μ μ€λ¬΄μμ μ μ©ν΄ κ°λ°μ μ§ννλ €λ©΄ μ΅μν κ°λ μ λλ νμ μ νκ³ μμ΄μΌ νκΈ° λλ¬Έμ λλ€.
π― λμμΈ ν¨ν΄
λ¨Όμ μ±κΈν΄ ν¨ν΄μ λν΄ μ΄ν΄λ³΄κΈ°μ , λμμΈν¨ν΄μ λν΄ κ°λ΅ν μ΄ν΄λ³΄κ² μ΅λλ€.
λ무μν€μμ λμμΈ ν¨ν΄μ κ°μ²΄ μ§ν₯ νλ‘κ·Έλλ° μ€κ³λ₯Ό ν λ μμ£Ό λ°μνλ λ¬Έμ λ€μ νΌνκΈ° μν΄ μ¬μ©λλ ν¨ν΄ μ΄λΌκ³ μ μνκ³ μμ΅λλ€. λμμΈ ν¨ν΄μ μ μ ν 격μΈμΌλ‘ 'λ°ν΄λ₯Ό λ€μ λ°λͺ νμ§ λ§λΌ(Don't reinvent the wheel)' λΌλ λ§μ΄ μμ΅λλ€. μ΄ λ§μ μ΄λ―Έ λ§λ€μ΄μ Έμ μ λλ κ²μ μ²μλΆν° λ€μ λ§λ€ νμκ° μλ€λ μλ―Έμ λλ€. μ¦, λΆνμνκ² μ²μλΆν° λ€μ μμν νμκ° μλ€λ κ²μ μλ―Έν©λλ€.
ν¨ν΄(Pattern)μ΄λ, 'μΌμ ν ννμ μμμ΄λ μ ν'μ μλ―Έν©λλ€. μ 리ν΄λ³΄μλ©΄, μ΄λ€ λΉμ·νκ±°λ λμΌν μμ λλ μ νλ€μ΄ λ°λ³΅λμ΄ λνλλ€λ μλ―Έλ‘λ ν΄μν μ μμ΅λλ€. μ¬κΈ°μ μ€μν μ μ λ°λ³΅λμ΄ λνλλ€λ μλ―Έμ λλ€. κ·Έλμ κ°λ°μ μ§ννλ©΄μ κ·κ° λ³λλ‘ λ€μ΄μλ λ§ μ€ νλκ° 'λ°λ³΅λλ μ½λλ₯Ό μμ±νμ§ λ§λΌ' μμ΅λλ€. λ€μν μννΈμ¨μ΄λ₯Ό κ°λ°ν λ μλ‘κ°μ 곡ν΅λλ μ€κ³ λ¬Έμ κ° μ‘΄μ¬νλ©°, μ΄λ₯Ό μ²λ¦¬νλ ν΄κ²°μ± μ¬μ΄μλ 곡ν΅μ μ΄ μ‘΄μ¬ν©λλ€.
λμμΈ ν¨ν΄μ ꡬ쑰λ μ½ν μ€νΈ(context), λ¬Έμ (problem), ν΄κ²°(solution) μ΄λΌλ 3κ°μ νμμ μΈ μμλ‘ κ΅¬μ±μ΄ λ©λλ€.
- μ½ν μ€νΈλ, λ¬Έμ κ° λ°μνλ μ¬λ¬ μν©μ κΈ°μ ν©λλ€. μ¦, ν¨ν΄μ΄ μ μ©λ μ μλ μν©μ λνλ λλ€. κ²½μ°μ λ°λΌμλ μ΄λ¬ν ν¨ν΄μ΄ μ μ©νμ§ λͺ»ν μν©λ μ‘΄μ¬ν©λλ€.
- λ¬Έμ λ, ν¨ν΄μ΄ μ μ©λμ΄ ν΄κ²°λ νμκ° μλ μ¬λ¬ λμμΈ μ΄μλ€μ κΈ°μ ν©λλ€. μ΄λ, μ¬λ¬ μ μ½ μ¬νκ³Ό μν₯λ ₯λ λ¬Έμ ν΄κ²°μ μν΄ κ³ λ €ν΄μΌ ν©λλ€.
- ν΄κ²°μ΄λ, λ¬Έμ λ₯Ό ν΄κ²°νλλ‘ μ€κ³λ₯Ό ꡬμ±νλ μμλ€κ³Ό κ·Έ μμλ€ μ¬μ΄μ κ΄κ³, μ± μ, νλ ₯ κ΄κ³λ₯Ό κΈ°μ ν©λλ€.
π μ±κΈν΄ ν¨ν΄
μμ λμμΈ ν¨ν΄μ λν΄ κ°λ΅ν μ€λͺ μ νμλλ°μ, μ΄μ μ±κΈν΄ ν¨ν΄μ λν΄ μμλ³΄κ² μ΅λλ€.
μ±κΈν΄ ν¨ν΄μ΄λ, μΈμ€ν΄μ€κ° μ€μ§ νλλ§ μμ±λλ κ²μ 보μ₯νκ³ μ΄λμλ λμΌν μΈμ€ν΄μ€μ μ κ·Όν μ μλλ‘ νλ λμμΈ ν¨ν΄μ λλ€.
μ±κΈν΄ ν¨ν΄μ μμ± ν¨ν΄μ ν μ’ λ₯λ‘, μμ± ν¨ν΄μ κ°μ²΄ μμ±μ κ΄λ ¨λ ν¨ν΄μΌλ‘ κ°μ²΄μ μμ±κ³Ό μ‘°ν©μ μΊ‘μνν΄ νΉμ κ°μ²΄κ° μμ±λκ±°λ λ³κ²½λμ΄λ νλ‘κ·Έλ¨ κ΅¬μ‘°μ μν₯μ ν¬κ² λ°μ§ μλ μ μ°μ±μ μ 곡ν©λλ€.
μΈμ€ν΄μ€κ° μ€μ§ νλλ§ μμ±λμ΄μΌ νλ μν©μ κ°μ νκΈ° μν΄, νμ€μΈκ³μμ νλ¦°ν°λ₯Ό μ¬μ©νλ μμλ₯Ό λ€μ΄λ³΄κ² μ΅λλ€.
AλΌλ νμ¬λ νμ¬ μ½λ‘λλ‘ μΈν΄ μ¬μ μ΄ λλμΉ μκΈ° λλ¬Έμ μμ°μ μ΅λν μ€μ¬μΌ ν©λλ€. μ΄λ₯Ό μν΄ μ¬λ΄μμ μ¬μ©λλ νλ¦°ν°λ ν λλ₯Ό μ μΈνκ³ λͺ¨λ μ²λΆμ ν΄λ²λ Έμ΅λλ€. λ°λΌμ λͺ¨λ μ§μλ€μ λμΌν νλ¦°ν° ν λλ§ κ³΅μ ν΄μ μ¬μ©μ ν΄μΌ ν©λλ€.
μ΄λ₯Ό κ°λ¨νκ² μ½λλ‘€ λνλ΄λ³΄κ² μ΅λλ€.
public class Printer {
private static Printer printer;
// μΈμ€ν΄μ€νλ₯Ό λ§λλ€.
private Printer() { }
// μ±κΈν΄ ν¨ν΄(λ¨μΌ μΈμ€ν΄μ€)
public static Printer getInstance() {
if (printer == null) {
printer = new Printer();
}
return printer;
}
public void print(final String message) {
System.out.println(message);
}
}
public class User {
private final String name;
public User(String name) {
this.name = name;
}
public void print() {
Printer printer = Printer.getInstance();
printer.print(this.name + " print using " + printer);
}
}
import org.junit.jupiter.api.Test;
class PrinterTest {
@Test
void λ¨μΌ_μ€λ λ_νλ¦°ν°() {
final int userNumber = 5;
User[] users = new User[userNumber];
for (int i = 0; i < userNumber; i++) {
users[i] = new User((i + 1) + "-user");
users[i].print();
}
}
}
νμ¬ Printer ν΄λμ€μ κ°μ²΄λ privateμ ν΅ν΄ μΈλΆμμ μμ±μ΄ λΆκ°λ₯νκ³ λ΄λΆμ getInstance() λ©μλλ₯Ό ν΅ν΄μλ§ κ°λ₯ν©λλ€.
λν μ κ²°κ³Όλ₯Ό 보면 5κ°μ Printer μΈμ€ν΄μ€κ° μ λΆ λμΌνκ² μΆλ ₯μ΄ λλκ²μ νμΈν μ μμ΅λλ€.
⻠보ν΅, μ±κΈν΄ ν¨ν΄μ λνλΌλ λ©μλλ getInstance()λΌλ μ΄λ¦μ μ¬μ©νκ³€ ν©λλ€.
λ°λΌμ μμ κ°μ΄ μ½λλ₯Ό μμ±νλ©΄ λλ κ² κ°μ§λ§, μ€μ λ‘λ λ¬Έμ μ μ΄ λ§μ΄ μ‘΄μ¬ν©λλ€.
μλμμ μ’ λ μ΄ν΄λ³΄κ² μ΅λλ€.
π λ¬Έμ μ
μ νλ¦°ν°λ λͺ¨λ μΈμ€ν΄μ€κ° λμΌνκΈ° λλ¬Έμ μ±κΈν΄ ν¨ν΄μ λ§μ‘±νλ κ² μ²λΌ 보μ΄μ§λ§, μ€μ λ‘λ κ·Έλ μ§ μμ΅λλ€.
λ©ν° μ€λ λμ νκ²½μμλ λ¬Έμ κ° λ°μν μ μλλ°μ, λ€μκ³Ό κ°μ μλ리μ€κ° μ‘΄μ¬ν μ μμ΅λλ€.
- Printer μΈμ€ν΄μ€κ° μμ±λμ§ μμμ λ μ€λ λ Aκ° getInstance() λ©μλλ₯Ό νΈμΆν΄ μΈμ€ν΄μ€κ° μμ±λμλμ§ νμΈν©λλ€.
- μμμ μ€λ λ Aκ° μμ±μλ₯Ό νΈμΆν΄ μΈμ€ν΄μ€λ₯Ό λ§λ€κΈ° μ , μ€λ λ Bκ° getInstance() λ©μλλ₯Ό νΈμΆν΄ ifλ¬Έμ μ€ννλ€λ©΄, νμ¬ Printer μΈμ€ν΄μ€λ nullμ΄λ―λ‘ μΈμ€ν΄μ€κ° μμ±μ΄ λ©λλ€.
- λ§μ°¬κ°μ§λ‘ μ€λ λ Aλ μΈμ€ν΄μ€λ₯Ό μμ±νκΈ° λλ¬Έμ λ€λ₯Έ μΈμ€ν΄μ€κ° μμ±μ΄ λ©λλ€.
μ μλ리μ€λ κ²½ν© μ‘°κ±΄(race condition)μ λ°μν€λλ°, κ²½ν© μ‘°κ±΄μ΄λ λ©λͺ¨λ¦¬μ κ°μ λμΌν μμμ 2κ° μ΄μμ μ€λ λκ° μ΄μ©νλ €κ³ κ²½ν©νλ νμμ μλ―Έν©λλ€.
λ©ν° μ€λ λ νκ²½μμμ μ½λλ₯Ό μ΄ν΄λ³΄κ² μ΅λλ€.
public class Printer {
...
public static Printer getInstance() {
if (printer == null) {
try {
Thread.sleep(1);
} catch (InterruptedException ignored) { }
printer = new Printer();
}
return printer;
}
public class UserThread extends Thread {
public UserThread(String name) {
super(name);
}
@Override
public void run() {
Printer printer = Printer.getInstance();
printer.print(Thread.currentThread().getName() + " print using " + printer);
}
}
@Test
void λ€μ€_μ€λ λ_νλ¦°ν°() {
UserThread[] userThreads = new UserThread[NUMBER];
for (int i = 0; i < NUMBER; i++) {
userThreads[i] = new UserThread((i + 1) + "-thread");
userThreads[i].start();
}
}
Printer ν΄λμ€μ getInstance() λ©μλμμ μ€λ λ μ€νμ κ³ μμ μΌλ‘ 1msλμ μ μ§νλλ‘ μ€μ νμμ΅λλ€.
κ·Έ ν Threadλ₯Ό μμλ°λ UserThread ν΄λμ€λ₯Ό μμ±νκ³ , ν μ€νΈλ₯Ό ν΄λ³΄λ©΄ λ€μκ³Ό κ°μ΅λλ€.
μ λ©ν° μ€λ λμ κ²°κ³Όλ₯Ό μ΄ν΄λ³΄λ©΄ λͺ¨λ λ€λ₯Έ μΈμ€ν΄μ€κ° μμ±μ΄ λλκ±Έ νμΈν μ μμ΅λλ€.
π ν΄κ²°λ°©λ²
κ°μ²΄μ μ΄λ₯Έ μ΄κΈ°ν(eager initialization) μ¬μ©νκΈ°
κ°μ²΄λ₯Ό lazyνκ² μμ±νλ λμ 미리 μμ±νλ(μ΄λ₯Έ μ΄κΈ°ν) λ°©λ²μ΄ μ‘΄μ¬ν©λλ€.
public class Printer {
private static final Printer INSTANCE = new Printer();
private Printer() { }
public static Printer getInstance() {
return INSTANCE;
}
}
μ κ²°κ³Όλ₯Ό μ΄ν΄λ³΄λ©΄ λ©ν° μ€λ λ νκ²½μμ λͺ¨λ λμΌν μΈμ€ν΄μ€κ° μμ±μ΄ λλκ²μ νμΈν μ μμ΅λλ€.
νμ§λ§ μ λ°©λ² λν μΈμ€ν΄μ€λ₯Ό μμ±νλ κ³Όμ μ΄ μ€λκ±Έλ¦¬κ³ λ©λͺ¨λ¦¬λ₯Ό λ§μ΄ μ¬μ©νλλ° λ°ν΄ κ°μ²΄λ₯Ό μ¬μ©νμ§ μλλ€λ©΄ μ΄λν λ¬Έμ μ μ΄ λ°μν μ μμ΅λλ€.
synchronized ν€μλ μ¬μ©νκΈ°
public static synchronized Printer getInstance() {
...
μμ κ°μ΄ μ¬μ©νκ³ μ νλ λ©μλμ synchronized ν€μλλ₯Ό μ¬μ©νλ©΄ ν΄κ²°ν μ μμ΅λλ€.
β» synchronized ν€μλ μΈμλ λ³μμ volatile ν€μλλ Atomic ν΄λμ€λ₯Ό μ΄μ©ν μλ μμ΅λλ€.
κ²°κ³Όλ₯Ό νμΈν΄λ³΄λ©΄ λͺ¨λ λμΌν μΈμ€ν΄μ€κ° μμ±μ΄ λλκ±Έ νμΈν μ μμ΅λλ€.
β» synchronized ν€μλμ λν΄μλ μλ ν¬μ€ν μ μμΈν μ€λͺ μ΄ λμ΄μμ΅λλ€.
νμ§λ§ μμ κ°μ΄ λ©μλ λΈλ‘μ synchronizedλ₯Ό ν΅ν΄ λκΈ°νλ₯Ό νλ©΄ κ·Ήλ¨μ μΈ κ²½μ°μμλ μ±λ₯μ΄ 100λ°° μ΄μ μ νλ μ μλ€κ³ ν©λλ€.
double check locking
μμ κ°μ λ¬Έμ μ μ double check lockingμ΄λΌλ λ°©λ²μ ν΅ν΄ ν΄κ²°ν μ μμ΅λλ€.
double check lockingμ΄λ, μ΄λ¦μ ν΅ν΄ νμ μν΄λ³΄λ©΄ lockingμ λλΈ μ²΄ν¬νλ κ°λ μ λλ€.
public class Printer {
private static Printer printer;
private Printer() { }
public static Printer getInstance() {
if (printer == null) {
synchronized (Printer.class) {
if (printer == null) {
printer = new Printer();
}
}
}
return printer;
}
}
λ©μλ λΈλ‘μμ synchronizedλ₯Ό ν΅ν λκΈ°νλ ν΄λΉ λ©μλλ₯Ό νΈμΆν λλ§λ€ λκΈ°νλ₯Ό νλ λ°λ©΄, μ μ½λλ λ©μλ λ΄λΆμμ Printer μΈμ€ν΄μ€κ° nullμΌ λλ§ λκΈ°νλ₯Ό μ€μ νκ² λ©λλ€.
λ°λΌμ λ©μλλ₯Ό νΈμΆν λλ§λ€ λκΈ°νλ₯Ό νλ μ½λλ³΄λ¨ μ±λ₯λ©΄μμ μ΄μ μ΄ μμ΅λλ€.
νμ§λ§ μ μ½λλ λ¬Έμ μ μ΄ μ‘΄μ¬νλ€κ³ νλλ°μ, μν€λ¬Έμμμλ λ€μκ³Ό κ°μ΄ μ΄μΌκΈ°λ₯Ό νκ³ μμ΅λλ€.
- Thread A notices that the value is not initialized, so it obtains the lock and begins to initialize the value.
- Due to the semantics of some programming languages, the code generated by the compiler is allowed to update the shared variable to point to a partially constructed object before A has finished performing the initialization. For example, in Java if a call to a constructor has been inlined then the shared variable may immediately be updated once the storage has been allocated but before the inlined constructor initializes the object.
- Thread B notices that the shared variable has been initialized (or so it appears), and returns its value. Because thread B believes the value is already initialized, it does not acquire the lock. If B uses the object before all of the initialization done by A is seen by B (either because A has not finished initializing it or because some of the initialized values in the object have not yet percolated to the memory B uses (cache coherence)), the program will likely crash.
μμμ μΈκΈνκ³ μλ λ¬Έμ μ μ λν΄ μ μ νμ¬ μ§μμΌλ‘λ μ΄ν΄νκΈ° νλ λΆλΆμ΄ λ§μ§λ§, μ κ° μ΄ν΄ν λ°λ‘λ λ©ν° μ€λ λ νκ²½μμ μ€λ λ Aμ μ€λ λ Bκ° μΈμ€ν΄μ€μ μμ±μ΄ λμ§ μμμΌλ μμ±μ΄ λμλ€κ³ νλ¨νλ μΈμ€ν΄μ€ μμ± λ° μ΄κΈ°ν κ³Όμ μμμ μΆ©λμ΄ λ°μν μ μλ€κ³ λ§νλ κ² κ°μ΅λλ€.
(μλͺ»λ λ΄μ©μ΄ μλ€λ©΄ λ§μν΄μ£Όμλ©΄ κ°μ¬νκ² μ΅λλ€ (__) π)
λ°λΌμ μ μ½λμμ printer λ³μμ volatileμ μ μΈν΄μ£Όλ©΄ ν΄κ²°μ΄ λ©λλ€.
private static volatile Printer printer;
...
volatile ν€μλλ μλ° λ³μλ₯Ό 'λ©μΈ λ©λͺ¨λ¦¬μ μ μ₯ ν΄μΌν 'νμμΌλ‘ μ¬μ©ν©λλ€. μ΄λ¬ν volatileμ λ³μμ κ°μμ±(Visibility)μ 보μ₯νλλ°μ, volatile ν€μλμ λν΄ μμΈν λ΄μ©μ μλ λ§ν¬λ₯Ό μ°Έκ³ ν΄μ£ΌμΈμ.
νμ§λ§ μμ κ°μ μ½λλ Java 1.4κΉμ§λ λ¬Έμ κ° λ°μν μ μμ΅λλ€.(Java 17μ΄ λμ¨ λ§λΉμ java 1.4κ° μμκΉ μΆκΈ΄ ν©λλ€λ§..)
Java 1.4κΉμ§ volatile ν€μλλ μ΄μ μ μ½νκ±°λ μ°μΈ κ°μ΄ μ»΄νμΌλ¬μ μν΄ μ¬μ λ ¬μ΄ λ μ μκ³ , μ΄λ‘ μΈν΄ double check lockingμμ λ¬Έμ κ° λ°μν μ μλ€κ³ ν©λλ€. μ΄λ Java 1.5λΆν°λ λ³κ²½μ΄ λμκΈ°λλ¬Έμ, Java 1.5λΆν°λ μ κ²½μ°μ§ μμλ λ©λλ€.
static classλ₯Ό ν΅ν μ§μ° μ΄κΈ°ν
μμμ μ΄ν΄λ΄€λ ν΄κ²°μ± λ€μ κ½€λ 볡μ‘ν λ°©λ²λ€μ λλ€. Java λ²μ μ νμΈν΄μΌνλ©°, volatile ν€μλμ synchronized ν€μλμ λν΄μλ μ΅λνκ³ μμ΄μΌ μ½λλ₯Ό μ΄ν΄νκ³ μ¬μ©ν μ μμ΅λλ€.
κ·ΈλΌ μ’ λ κ°νΈν λ°©λ²μ μμκΉμ? π€ μλ μ½λλ₯Ό μ΄ν΄λ³΄κ² μ΅λλ€.
public class Printer {
private Printer() { }
private static class PrinterHolder {
public static final Printer printer = new Printer();
}
public static Printer getInstance() {
return PrinterHolder.printer;
}
}
μ μ½λλ λ΄λΆ ν΄λμ€μΈ PrinterHolderκ° νΈμΆμ΄ λ λκΉμ§ λ‘λκ° λμ§ μλλ€λ μ¬μ€μ μμ‘΄ν©λλ€.
λ°λΌμ λ©ν° μ€λ λ νκ²½μμλ μμ νκ³ , getInstance() λ©μλλ₯Ό νΈμΆν λ PrinterHolder ν΄λμ€λ₯Ό νΈμΆνκΈ° λλ¬Έμ μ§μ° μ΄κΈ°νλ κ°λ₯νκ² λ©λλ€. λν μ΄μ μ μ΄ν΄λ΄€λ double check lockingμ κ°μ΄ μ½λκ° λ³΅μ‘νμ§ μ΅λλ€.
μ€μ μ μ½λλ₯Ό κΈ°λ°μΌλ‘ ν μ€νΈλ₯Ό ν΄λ³΄λ©΄ μμκ°μ΄ λͺ¨λ λμΌν μΈμ€ν΄μ€κ° μμ±μ΄ λ©λλ€.
λ©ν° μ€λ λμμ μμμ 곡μ νλ static class
λ©ν° μ€λ λ νκ²½μμ μμμ 곡μ νλ©΄ λκΈ°νκ° λλμ§ ν μ€νΈν΄λ³΄κ² μ΅λλ€.
public class StaticPrinter {
private static int counter = 0;
public synchronized static void print(final String str) {
counter++;
System.out.println(str + " " + counter);
}
}
public class StaticUserThread extends Thread {
public StaticUserThread(String name) {
super(name);
}
public void run() {
StaticPrinter.print(Thread.currentThread().getName() + " print using ");
}
}
class StaticPrinterTest {
private static final int NUMBER = 5;
@Test
void μμμ_곡μ νλ_λ©ν°_μ€λ λ() {
StaticUserThread[] user = new StaticUserThread[NUMBER];
for (int i = 0; i < NUMBER; i++) {
user[i] = new StaticUserThread((i + 1) + "-thread");
user[i].start();
}
}
}
μ μ½λμ κ²°κ³Όλ₯Ό 보면 counter λ³μκ° 1μ© μ¦κ°νλ κ²μ νμΈν μ μμ΅λλ€.
κ·ΈλΌ νμ static classλ₯Ό μ¬μ©νλ©΄ λ κΉ?
μ¬λ¬ μλ£λ€μ μ°Ύμ보λ νμ κ·Έλ μ§λ μλ€κ³ ν©λλ€.
μ μ ν΄λμ€λ₯Ό μ΄μ©νλ λ°©λ²κ³Ό μ±κΈν΄ ν¨ν΄μ μ΄μ©νλ λ°©λ²μ€ κ°μ₯ μ°¨μ΄κ° λλ μ μ κ°μ²΄λ₯Ό μ ν μμ±νμ§ μκ³ μ μ λ©μλλ₯Ό μ¬μ©νλ€λ μ μΈλ°μ(μ½λκ° κΆκΈνμλ©΄ java.lang.Math ν΄λμ€λ₯Ό μ°Έκ³ ν΄λ³΄μλ©΄ μ’μ κ² κ°μ΅λλ€.) μ κ²°κ³Όμμ νμΈν μ μλ―μ΄ λ¬Έμ μμ΄ counter λ³μκ° μ€λ λ 5κ°μμ μμ νκ² κ³΅μ λμ΄ μ¬μ©λ μ μμμ μ μ μμ΅λλ€. λμ±μ΄ μ μ λ©μλλ₯Ό μ¬μ©νλ―λ‘ μΌλ°μ μΌλ‘ μ€νν λ λ°μΈλ©λλ(μ»΄νμΌ νμ λ°μΈλ©) μΈμ€ν΄μ€ λ©μλλ₯Ό μ¬μ©νλ κ²λ³΄λ€ μ±λ₯λ©΄μμλ μ°μνλ€κ³ ν μ μμ΅λλ€.
μ±κΈν΄ ν¨ν΄μ κ²½μ° static classμλ λ¬λ¦¬ κ°μ²΄ λ΄λΆμ 곡μ νλ μμμ΄ μμλ μ μ©νλ°, μλ₯Όλ€μ΄ λ°μ΄ν°λ² μ΄μ€λ in-memory μΊμ λ±κ³Ό κ°μ μνλ€μ΄ μμ΅λλ€. μ¦, νλ‘κ·Έλ¨μ μ¬λ¬ κ³³μμ μμ κ°μ 곡μ μμλ€μ μ¬μ©νκΈ°λ₯Ό μνκ³ , λ¨μΌ μ§μ (single point)λ₯Ό ν΅νμ¬ μ΄λ¬ν μμλ€μ λν΄ μ κ·Όνκ³ μ ν λ μ μ©νλ€κ³ ν©λλ€.
μμ λ΄μ©λ€μ μ κ° κ²½νν΄λ³΄μ§λ λͺ»ν μλ λ§ν¬λ€μ μ°Έκ³ νμ¬ μμ±νμμ΅λλ€. νλ¦° λ΄μ©μ΄ μλ€λ©΄ νΌλλ°± λΆνλ립λλ€.
- When to use a Singleton and when to use a static class [duplicate]
- Difference between Singleton Pattern vs Static Class in Java? Example
βοΈ μ 리
λμμΈ ν¨ν΄ λ° μ±κΈν΄ ν¨ν΄μ λν΄ μμ보μμ΅λλ€. κ·Έλμ μ±κΈν€ ν¨ν΄μ λ¨μν 'μΈμ€ν΄μ€κ° μ€μ§ νλλ§ μμ±λλ€.' λΌλ κ°λ λ§ μκ³ μ§λ΄μμΌλ©° μΈμ€ν΄μ€λ₯Ό μΈλΆμμ μμ±ν μ μλλ‘ μμ±μλ₯Ό privateλ‘ λ§κ³ μ μ λ©μλ(getInstance)λ₯Ό ν΅ν΄ μΈμ€ν΄μ€λ₯Ό μμ±ν μ μλ€. λΌλ μ λλ‘λ§ μκ³ μμμ΅λλ€. μ΄λ² μ 리λ₯Ό ν΅ν΄ μ±κΈν΄ ν¨ν΄μ λν΄ μ’ λ κΉκ² 곡λΆνκ³ μ μ¬λ¬ μλ£λ€κ³Ό μμλ€μ μ°Έκ³ ν΄λ³΄μμ΅λλ€.
ν¬μ€ν μμ μ€λͺ λλ¦° κ²μ²λΌ μ±κΈν΄ ν¨ν΄μ ꡬννλ λ°©μμλ μ¬λ¬κ°μ§κ° μ‘΄μ¬νλ©°, μ΄μ κ΄λ ¨ν΄μ synchronized, volatileμ κ°μ ν€μλλ double check locking λ±λ±μ μ©μ΄μ λν΄μλ νμ΅ν μ μλ μκ°μ΄μμ΅λλ€.
π References
- https://namu.wiki/w/%EB%94%94%EC%9E%90%EC%9D%B8%20%ED%8C%A8%ED%84%B4
- JAVA κ°μ²΄ μ§ν₯ λμμΈ ν¨ν΄
- https://www.youtube.com/watch?v=bHRETd1rFfc
- https://en.wikipedia.org/wiki/Double-checked_locking
- https://stackoverflow.com/questions/10336006/using-volatile-keyword-in-java4-and-java5
- https://softwareengineering.stackexchange.com/questions/235527/when-to-use-a-singleton-and-when-to-use-a-static-class
- https://javarevisited.blogspot.com/2013/03/difference-between-singleton-pattern-vs-static-class-java.html#axzz7A17KIg6U%EF%BB%BF
- https://javarevisited.blogspot.com/2012/03/what-is-static-and-dynamic-binding-in.html#axzz7AAlNMjhN
'Java' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[Java DeepDive] - String (2) λ΄μ₯ ν¨μ (0) | 2022.10.23 |
---|---|
[Java DeepDive] - String (1) λ¬Έμμ΄ μμ± (0) | 2022.10.10 |
[Java] - κΉμ 볡μ¬(Deep Copy) vs μμ 볡μ¬(Shallow Copy) (1) | 2021.07.30 |
[Java] - Project Lombok(둬볡) (0) | 2021.06.20 |
[Java] - Jsoupμ μ΄μ©ν ν¬λ‘€λ§(feat. μΈνλ°) (5) | 2021.05.11 |
λκΈ