///////
Search
💫

Java의 synchronized Lock 범위에 대해서 알려주세요. (Class Lock, Instance Lock)

Lock 의 범위 - 개념

동기화를 위해 Lock을 한단 개념은 다들 알고 있을 것이다.
이때, Lock의 범위를 지정해 줄 수도 있는데, class / instance 로 나누어 볼 수 있다.
Object level lock
Class level lock
static
non - staic 데이터를 thread safe하게 만들 때 사용
static 데이터를 thread safe하게 만들기 위해서 사용
범위
클래스의 모든 인스턴스가 각자의 lock을 가질 수 있다.
클래스 하나당 하나의 lock만 존재한다.
public class ObjectLevelLockExample { public void objectLevelLockMethod() { synchronized (this) { } } } public class ClassLevelLockExample { public void classLevelLockMethod() { synchronized (ClassLevelLockExample.class) { } } }
Java
복사

Lock 의 범위 - 코드

Object level lock
예제 1) 인스턴스 한개 / 두개 생성에 따른 차이
public class A { public synchronized void run(String name) { System.out.println(name + "락 걸기"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name + "락 해제"); } }
Java
복사
public class hello { public static void main(String[] args) { A a = new A(); // 인스턴스는 하나. Thread thread1 = new Thread( () -> { a.run("thread-1"); }); Thread thread2 = new Thread( () -> { a.run("thread-2"); }); thread1.start(); // 쓰레드 2개 thread2.start(); } }
Java
복사
결과 - 쓰레드 별로 lock을 획득/반납
이번엔 인스턴스를 하나 더 만들어서 각각 run을 해준다.
public class hello { public static void main(String[] args) { A a1 = new A(); // 인스턴스 두개 A a2 = new A(); Thread thread1 = new Thread( () -> { a1.run("thread-1"); }); Thread thread2 = new Thread( () -> { a2.run("thread-2"); }); thread1.start(); thread2.start(); } }
Java
복사
결과 - 동기화 X , Lock을 공유하지 않음
예제 2 ) class 안에 synchronized 블록 적용에 따라 달라지는 lock 공유 여부
public class A { public synchronized void run(String name) { System.out.println(name + "락 걸기"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name + "락 해제"); } public void print(String name) { System.out.println(name + "hi"); } }
Java
복사
public class hello { public static void main(String[] args) throws InterruptedException { A a = new A(); Thread thread1 = new Thread( () -> { a.run("thread-1"); }); Thread thread2 = new Thread( () -> { a.print("thread-2"); }); thread1.start(); Thread.sleep(500); thread2.start(); } }
Java
복사
결과 - 동기화 X
이번엔 print() 메서드도 synchronized 키워드를 붙여본다.
public class A { public synchronized void run(String name) { System.out.println(name + "락 걸기"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name + "락 해제"); } public synchronized void print(String name) { // 🔴 print()메서드도 synchronized 적용 System.out.println(name + "hi"); } }
Java
복사
결과 - 동기화 발생
예시2의 실습을 통해 ,
synchronized가 적용된 모든 object에 대해서 lock을 공유한다는 것을 알 수 있다.
Class level lock
아까와 같이 인스턴스를 2개 생성한 채, synchronized 메서드 앞에 static만 붙여줬다.
public class hello { public static void main(String[] args) throws InterruptedException { A a1 = new A(); A a2 = new A(); Thread thread1 = new Thread( () -> { a1.run("thread-1 "); }); Thread thread2 = new Thread( () -> { a2.run("thread-2 "); }); thread1.start(); Thread.sleep(500); thread2.start(); }
Java
복사
public class A { public static synchronized void run(String name) { System.out.println(name + "락 걸기"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name + "락 해제"); } }
Java
복사
결과
instance lock에서 인스턴스를 2개 만들면, 인스턴스끼리 동기화가 되지 않던 것과 달리 동기화가 잘 된다.
→ 클래스 단위로 lock이 발생하기 때문
그렇다면 static synchronized method와 synchronized method 둘 다의 경우를 보기 위해 코드를 추가해본다.
public class hello { public static void main(String[] args) throws InterruptedException { A a1 = new A(); A a2 = new A(); Thread thread1 = new Thread( () -> { a1.run("thread-1 "); }); Thread thread2 = new Thread( () -> { a2.print("thread-2 "); }); thread1.start(); Thread.sleep(500); thread2.start(); } }
Java
복사
public class A { public static synchronized void run(String name) { // static System.out.println(name + "락 걸기"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(name + "락 해제"); } public synchronized void print(String name) { // non-static System.out.println(name + "hi"); } }
Java
복사
결과
두 메서드 다 synchronized 키워드가 붙어 있어, 동기화가 될 것 같지만 이건 인스턴스 단위의 관점이고,
클래스 단위에선 위와 같은 상황에서 lock이 공유되지 않는다.