Synchronization

장석빈·2022년 6월 7일
0


2개의 Thread A, B가 동시에 공유자원 printer를 사용할 경우 Thread Interfenrence(스레드 간섭)이 발생함.

ex1-1)스레드 간섭 예제

Printer.class

public class Printer {
    //문자열을 한 글자당 1초씩 소요하며 출력
    public void println(String str) {
        for (char c : str.toCharArray()) {
            System.out.print(c);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {

            }
        }
        System.out.println();
    }
}

SharedPrinterEx.class

public class SharedPrinterEx {
    public static void main(String[] args) {
        Printer printer = new Printer();

        //프린터를 사용하는 스레드들
        new Thread(() -> printer.println("ABCDEF")).start();
        new Thread(() -> printer.println("abcdef")).start();
    }
}

출력

AaBbCcdDEefF//Thread Interfenrence 발생!

Thread Interfenrence를 막기 위해서 syncronized를 사용한다!

ex1-2)syncronized

Printer.class

public class Printer {
    //문자열을 한 글자당 1초씩 소요하며 출력
    public synchronized void println(String str) {
        for (char c : str.toCharArray()) {
            System.out.print(c);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {

            }
        }
        System.out.println();
    }
}

SharedPrinterEx.class

public class SharedPrinterEx {
    public static void main(String[] args) {
        Printer printer = new Printer();

        //프린터를 사용하는 스레드들
        new Thread(() -> printer.println("ABCDEF")).start();
        new Thread(() -> printer.println("abcdef")).start();
    }
}

출력

ABCDEF
abcdef

한 스레드가 공유자원 사용을 마치고 다음 스레드가 사용할 수 있도록 syncronized(동기화)된다!

ex2-1)화장실 사용

RestRoom.class


public class RestRoom {
    //화장실을 사용하는데 1초가 걸림.
    public void use() {
        System.out.printf("%s : 화장실에 들어갔다\n", Thread.currentThread());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("%s : 화장실에 나왔다.\n", Thread.currentThread());
    }
}

SharedRestRoomEx.class

public class RestRoom {
    //화장실을 사용하는데 1초가 걸림.
    public void use() {
        System.out.printf("%s : 화장실에 들어갔다\n", Thread.currentThread());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("%s : 화장실에 나왔다.\n", Thread.currentThread());
    }
}

출력

Thread[Thread-0,5,main] : 화장실에 들어갔다
Thread[Thread-1,5,main] : 화장실에 들어갔다
Thread[Thread-2,5,main] : 화장실에 들어갔다
Thread[Thread-1,5,main] : 화장실에 나왔다.
Thread[Thread-2,5,main] : 화장실에 나왔다.
Thread[Thread-0,5,main] : 화장실에 나왔다.
//화장실에 동시에 2명이 들어가있는 불상사가 발생(Thread Interference)

ex2-2)synchronized

RestRoom.class


public class RestRoom {
    //화장실을 사용하는데 1초가 걸림.
    public synchronized void use() {
        System.out.printf("%s : 화장실에 들어갔다\n", Thread.currentThread());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("%s : 화장실에 나왔다.\n", Thread.currentThread());
    }
}

SharedRestRoomEx.class

public class RestRoom {
    //화장실을 사용하는데 1초가 걸림.
    public void use() {
        System.out.printf("%s : 화장실에 들어갔다\n", Thread.currentThread());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.printf("%s : 화장실에 나왔다.\n", Thread.currentThread());
    }
}

출력

Thread[Thread-0,5,main] : 화장실에 들어갔다
Thread[Thread-0,5,main] : 화장실에 나왔다.
Thread[Thread-1,5,main] : 화장실에 들어갔다
Thread[Thread-1,5,main] : 화장실에 나왔다.
Thread[Thread-2,5,main] : 화장실에 들어갔다
Thread[Thread-2,5,main] : 화장실에 나왔다.
//화장실에 1명만 들어가있는 상태(Thread Interference발생하지 않음.)

sychronized는 주의해서 사용해야함.화징실의 경우는 공유하며 사용할 수 없지만 TV시청같은 경우는 동시에 시청해도 무방하므로 남발하면 안된다.

ex3)synchronized block

public class RestRoom {
    //화장실을 사용하는데 1초가 걸림.
    public void use() {
        synchronized (this) {//화장실 사용에만 동기화함.
            System.out.printf("%s : 화장실에 들어갔다\n", Thread.currentThread());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.printf("%s : 화장실에 나왔다.\n", Thread.currentThread());
        }
    try{//동기화되지 않은 부분
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
        System.out.printf("%s : 손을 씻었다.\n", Thread.currentThread().getName());
    }
}

메서드 내부에서 꼭 동기화가 필요한 부분만 동기화해야한다.

profile
회피형 인간의 개과천선기

0개의 댓글