
이번 주말에는 문래랑 노들섬에 갔다 왔다. 날이 좋아져서 그런지 사람이 정말 많았고, 바람이 선선하게 불어서 이제 봄이 가까워지고 있다는게 실감이났다. 노들섬에서는 특별한 것 없이 친구랑 걸어 다니면서 떠들기만 했는데, 그 순간이 너무 행복하게 느껴졌다.
데브코스를 시작하고 힘든 부분도 많았지만 확실히 좋은점도 생겼는데, 공부와 할일의 체계가 잡혔다는 점과, 무엇보다 일상의 이런 작은 행복들이 너무나 소중해 졌다는 거… (왜냐면 평일이 헬이니까)다시 한 주가 시작 됐지만 열심히 살다 보면 또 주말이 오니까 화이팅!
(그리고 월요일은 참 악랄한 요일이다… 한 주의 시작인데 야구까지 안한다니)
‘나’를 한번만 생성해 꺼내서 사용함
→ 같은 클래스로부터 여러개의 객체를 만들지 못하고 오직 하나의 객체만 유지 된다.
public class Singleton{
private static final Singleton INSTANCE = new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return INSTANCE;
}
}
volatile이 필요한 이유
각 스레드는 메인 메모리 로부터 값을 복사해 CPU 캐시 에 저장하여 작업한다. CPU 가 2개 이상이라면 멀티 스레드 환경에서 각 스레드는 서로 다른 CPU 에서 동작하고 있으며 이는 각 스레드가 같은 변수에 대해 읽기, 쓰기 동작을 수행할 시 각자의 CPU 캐시 에 메인 메모리 의 값과 다른 값을 갖고 있을 수 있게 된다.
하지만 자바에서 어떠한 변수에 volatile 키워드를 붙이면 해당 변수는 모든 읽기와 쓰기 작업이 CPU 캐시가 아닌 메인 메모리 에서 이루어지게 되고 이로써 해당 변수 값에 대해 가시성 을 보장할 수 있다.
synchronized가 필요한 이유
멀티스레드 환경에서는 여러 스레드가 변수나 컬렉션과 같은 공유 자원에 동시에 접근하면 문제가 발생할 수 있다.
→ synchronized를 이용하면 한번에 하나의 스레드만 접근이 가능해진다.(원자성 보장)
public synchronized void increment() {
count++;
}
public void increment() {
synchronized (this) {
count++;
}
}
public static synchronized void staticMethod() {
// 클래스 전체에서 한 번에 하나의 스레드만 실행 가능
}
public void increment() {
synchronized (Counter.class) { // 클래스 단위 락
count++;
}
}
싱글톤 패턴을 구현할 때 멀티스레드 환경에서 인스턴스가 두 개 생성되는 문제를 방지하려면 volatile과 synchronized를 적절히 사용해야 한다.
synchronized만 사용했을 경우
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance() {
if(instance == null) { // 1번
instance = new Singleton(); // 2번
}
return instance;
}
}
단일 쓰레드가 대상 메소드를 호출시작~종료까지 다른 쓰레드가 접근하지 못하도록 lock 을 하기 때문에 위와 같이 getInstance()메소드를 synchronized로 처리하면 멀티 쓰레드에서 동시 접근으로 인한 인스턴스 중복생성 문제는 해결되게 된다.
‼️
하지만, synchronized getinstance()의 경우 인스턴스를 리턴 받을 때마다 Thread 동기화 때문에 불필요하게 lock이 걸리게 되어 비용 낭비가 크다.
DCL(Double-Checked-Locking) + volatile 사용
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 첫 번째 체크 (락 없이 검사)
synchronized (Singleton.class) {
if (instance == null) { // 두 번째 체크 (락 내부에서 검사)
instance = new Singleton();
}
}
}
return instance;
}
}
DCL 패턴을 사용하면 최초 한 번만 synchronized를 수행하므로 성능과 안정성을 모두 보장할 수 있다.
최적의 방법 = volatile + synchronized를 조합한 DCL 패턴 사용
❓DCL은 또 뭔가
DCL(Double Checking Locking)은 ThreadSafe한 싱글톤 설계를 위한 방식 중 하나이다.
DCL Singleton
DCL singleton패턴은 getInstance() 내부에서 instance를 생성하는 경우만 부분적으로 synchronized 처리를 하여 생성과 획득을 분리한 획기적인 방법이다. 즉 인스턴스가 생성되어 있는지 확인해보고 인스턴스가 없는 경우 lock을 잡고 instance를 생성하는 방법이다.
→ 소스코드 논리적으로는 문제가 없지만 컴파일러에 따라서 재배치(reordering)문제를 야기한다.
쿠키와 세션은 HTTP 프로토콜의 특징이자 약점을 보완하기 위해 사용한다.
HTTP 프로토콜은 비연결지향과 무상태성이라는 특징을 가지고 있다.
따라서 서버와 클라이언트가 통신을 할 때 통신이 연속적으로 이어지지 않고 한 번 통신이 되면 끊어진다.
또한 통신이 끊어지면 상태정보가 유지되지 않기 때문에 매번 페이지를 이동할 때마다 로그인은 다시 하거나, 상품 선택 후 구매 페이지에서 선택한 상품의 정보가 없거나 하는 등의 문제가 발생할 수 있다.
이러한 문제를 해결하는 방법이 바로 쿠키와 세션이다.
Session
Session의 동작방식

Cookie
Key-Value쌍으로 구성되어 있는 데이터 파일Cookie의 동작방식

set-cookie: 를 통해 쿠키를 추가하여 응답쿠키의 기한이 정해져 있지 않고 명시적으로 지우지 않는다면 반 영구적으로 쿠키가 남아있다.
JSESSIONID (Cookie)
JSESSIONID vs JWT
JSESSIONID는 서버 기반의 세션 식별자로 서버에서 상태를 유지해야 하지만, JWT는 토큰 기반 방식으로 클라이언트가 인증 정보를 유지하므로 무상태(Stateless) 방식이다.
| 특징 | JSESSIONID (세션 기반) | JWT (토큰 기반) |
|---|---|---|
| 저장 위치 | 서버 세션 (메모리, DB) | 클라이언트 (쿠키, 로컬스토리지) |
| 인증 방식 | 상태 유지 (Stateful) | 상태 없음 (Stateless) |
| 보안 이슈 | 세션 하이재킹, 세션 고정 공격 | 토큰 탈취 시 위험 |
| 확장성 | 서버가 세션 관리 부담 | 서버 부담 적음 |
맨날 뭘 알아갈때마다 느끼지만 세상에 참 어려운게 많은 것 같다…
진짜 너무 궁금한게 있는데 대체 이런건 처음에 누가 만들기 시작하는 걸까..?
그리고 왜 만드는걸까^^