Synchronized Block & 동기화 순서

yshjft·2023년 1월 12일
0

Java, OOP

목록 보기
25/27

Synchronized Block

  • synchronized mehtod의 경우 동일한 인스턴스에 대하여 synchronized가 붙은 메서드를 모두 동일한 락을 걸어버린다.
  • 이 때 원하는 메서드만 그룹화(?)시켜서 락을 걸 수 있는 방식이 synchronized block이다.
  • 또한 메서드 내에서 필요한 부분에 대해서만 락을 걸 수 있다.

객체 인스턴스

by this

public class D {
    public void run(String name) {
        // 전처리 로직

		// 인스턴스의 블락 단위로 락을 건다
        // 동기화 시작
        synchronized (this) {
            System.out.println(name+" lock");
            try {
                Thread.sleep(1000);
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name+" unlock");
        }
        // 동기화 해제

        // 후처리 로직
    }
    
    public void print(String name) {
        System.out.println(name+" hello");
    }
}

by instance of B

public class A {
    B b = new B();

    public void run(String name) {
        synchronized (b) {
            System.out.println(name+" lock");
            b.run();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name+" unlock");
        }
    }

    public synchronized void print(String name) {
        System.out.println(name + " hello");
    }
}

서로 다른 인스턴스

public class Main {
   private static void synchronizedBlockDifferentInstance() {
        D d1 = new D();
        D d2 = new D();

        Thread thread1 = new Thread(() -> {
            d1.run("thread1");
        });
        Thread thread2 = new Thread(() -> {
            d2.run("thread2");
        });

        thread1.start();
        thread2.start();
    }
}
  • 서로 다른 인스턴스끼리 락을 공유하지 않는다.
  • 동기화 되지 않는다.

서로 같은 인스턴스

public class Main {
   private static void synchronizedBlock() {
        D d = new D();

        Thread thread1 = new Thread(() -> {
            d.run("thread1");
        });
        Thread thread2 = new Thread(() -> {
            d.run("thread2");
        });

        thread1.start();
        thread2.start();
    }
}
  • 동기화 된다.

서로 같은 인스턴스 & synchronized block & non-synchronized block

public class Main {
   private static void synchronizedAndNonSynchronized() {
        D d = new D();

        Thread thread1 = new Thread(() -> {
            d.run("thread1");
        });
        Thread thread2 = new Thread(() -> {
            d.print("thread2");
        });

        thread1.start();
        thread2.start();
    }
}
  • 동기화 안된다.

non this

public class Main {
    public static void synchronizedBlockByInstance() {
        A a = new A();
        Thread thread1 = new Thread(() -> {
            a.run("thread1");
        });
        Thread thread2 = new Thread(() -> {
            a.run("thread2");
        });
        Thread thread3 = new Thread(() -> {
            a.print("자원 B와 관련 없는 thread3");
        });

        thread1.start();
        thread2.start();
        thread3.start();
    }
}
  • thread1thread2는 동기화가 된다(b). 하지만 thread3는 동기화 되지 않는다(this).

클래스

public class E {
    public void run(String name) {
        synchronized (B.class) {
            System.out.println(name+" lock");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name+" unlock");
        }
    }
}
public class Main {
   public static void synchronizedBlockByClass() {
         // E e = new E();
         E e1 = new E();
         E e2 = new E();

        Thread thread1 = new Thread(() -> {
            e1.run("thread1");
        });
        Thread thread2 = new Thread(() -> {
            e2.run("thread2");
        });

        thread1.start();
        thread2.start();
    }
}
  • 같은 class로 lock이 걸렸다면 같은 인스턴스, 다른 인스턴스 상관 없이 동기화가 된다.

static 메서드에서 Synchronized Block을 사용

클래스 인자

public class F {
    public static void run(String name) {
        synchronized (B.class) {
            System.out.println(name + " lock");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + " unlock");
        }
    }
}

정적 인스턴스 인자

public class F {
    static B b = new B();

    public static void run(String name) {
        synchronized (b) {
            System.out.println(name + " lock");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(name + " unlock");
        }
    }
}
  • 인자로 this나 인스턴스 사용할 수 없다. 클래스 또는 정적 인스턴스를 인자로 사용할 수 있다.

synchronized 동기화 순서

  • synchronized는 동기화 순서를 보장하지 않는다.

참고

profile
꾸준히 나아가자 🐢

0개의 댓글