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 의 범위 - 코드
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
복사
이번엔 인스턴스를 하나 더 만들어서 각각 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
복사
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
복사
이번엔 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을 공유한다는 것을 알 수 있다.
아까와 같이 인스턴스를 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이 발생하기 때문
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이 공유되지 않는다.