[Java] Synchronized

He SEO·2022년 3월 15일
0

Multi-Thread로 동시 접근되는 것을 막는 개념.

Thread는 class의 멤버변수의 자원에 접근할 수 있는데, 이는 멤버 변수가 heap 메모리를 사용하기 때문임. 여러 thread가 공유 자원에 접근하는 경우 동기화를 해줘야 할 필요가 있어서 synchronized를 사용. 추가적으로 synchronized 외에 volatile, atomic class를 사용할 수 있음.

Usage

  1. Make synchronized function
class BasicSynchronization {
    private String msg;
    
    public static void main(String[] args) {
        BasicSynchronization tmp = new BasicSynchronization();
        
        System.out.println("Test start");
        new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                tmp.callMe("Thread 1");
            }
        }).start();
        
        new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                tmp.callMe("Thread 2");
            }
        }).start();
        
        System.out.println("Test end!");
    }
    
    public synchronized void callMe(String whoCallMe) {
        msg = whoCallMe;
        
        try {
            long sleep = (long)(Math.random() * 100);
            Thread.sleep(sleep);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        if (!msg.equals(whoCallMe)) {
            System.out.println(whoCallMe + " | " + msg);
        }
    }
}
  • 두개의 thread를 만들어 synchronized callMe() 함수를 호출
  • callMe() 함수를 받아서 아래와 같은 작업 수행
  • parameter 값을 멤버 변수에 저장
  • 랜덤하게 sleep
  • 멤버 변수와 parameter 값이 같지 않으면 로깅

테스트 결과
절대 로그가 찍히지 않음. 하지만 synchronized 함수를 제거하면 로그가 찍힘.

결과
함수에 synchronized를 걸면 그 함수가 포함된 해당 객체에 lock을 거는 것과 동일.
단점이라면 객체에 포함된 다른 모든 synchronized의 접근까지 lock이 걸림.
이를 해결하기 위해 2번 방법이 존재.

  1. Use synchronized block
class SyncBlock1 {
    public ArrayList<Integer> mList = new ArrayList<>();

    public static void main(String[] args) {
        SyncBlock1 syncBlock1 = new SyncBlock1();
        System.out.println("Test start!");

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                syncBlock1.add(i);
            }
        });

        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                syncBlock1.add(i);
            }
        });

        t1.start();
        t2.start();

//        t1.join();
//        t2.join();

        System.out.println(syncBlock1.mList.size());
        System.out.println("Test end!");
    }

    public void add(int val) {
        synchronized(this) {
            if (mList.contains(val) == false) {
                mList.add(val);
            }
        }
    }
}
  • add() 함수 내부에 동기화가 필요한 부분에만 synchronized(this) 블록으로 처리
  • 두개의 thread로 동시에 생성한 syncBlock1 객체의 add() 함수 호출

Singleton 객체에서의 동기화

Singleton은 객체를 한개만 생성하여 사용하도록 함. Multi-thread 환경과 동일하게 동작함.

static 함수에서의 동기화

static 함수라도 함수간 동기화가 잘 지켜지며, 해당 class에 lock을 검.
만약 synchronized static과 static을 함께 사용한다면 꼬일 수 있음.

참고 사이트

profile
BACKEND 개발 기록 중. 감사합니다 😘

0개의 댓글