티스토리 뷰

 Java 스레드 동기화 빠르게 보기!


1.임계구역

1
2
3
4
5
6
7
    synchronized (java.lang.Object.class) {
        System.out.println("----------Start Working!----------");
        for(int i =0;i<100000000;i++){
        System.out.println(i);
        }
        System.out.println("----------Finish Working!----------");
    }
cs


2.메소드

1
2
3
4
5
6
7
    public synchronized void doWork(){
        System.out.println("----------Start Working!----------");
        for(int i =0;i<100000000;i++){
        System.out.println(i);
        }
        System.out.println("----------Finish Working!----------");
    }
cs



동기화란?

한 마디로 작업들 사이의 수행 시기를 맞추는 것 입니다. 멀티 스레드 환경에서 하나의 객체를 사용할 때를 예시로 들어보겠습니다.



두 스레드가 하나의 Object 객체의 data에 접근하는 경우 입니다. 만약 위의 두 스레드를 동시에 실행을때 Thread1data5를 넣고 출력하는 사이에 Thread2가 data10으로 바꿔버린다면 Thread1에서는 5가 아닌 10이 출력되는 문제가 발생할 수 있습니다.


이처럼 하나의 데이터에 여러곳에서 접근하게 될때 데이터의 일관성에 문제가 생기는것을 방지하기 위해서 스레드 동기화를 하게 됩니다. 위의 경우에 스레드 동기화를 하게 되면 Thread1이 작업중일때는 Thread2가 data를 건드릴 수 없고, Thread2가 작업중일 때는 Thread1이 data를 건드릴 수 없게 됩니다.




 스레드 동기화 기법의 종류

스레드 동기화 기법은 유저 모드 동기화와 커널 모드 동기화 두 가지로 나뉘게 됩니다.



유저모드 동기화

유저 모드 동기화(Synchronization in User Mode)에는 Critical Section(임계 영역) Object를 사용하고 커널 모드 동기화에 비해 빠르다는 장점이 있습니다. 커널모드는 연산 모드를 유저모드에서 커널모드로 변경해야 하기 때문에 상대적으로 유저 모드 동기화보다 느리지만 유저모드 동기화는 유저 모드에서 동기화가 이루어지기 때문에 모드 전환에 대한 부담이 없습니다. 하지만 단일 프로세스 내의 스레드 간의 동기화만 제공되는 등의 기능이 제한되고, Deadlock(교착상태)이 발생하기 쉽습니다.



커널모드 동기화

커널 모드 동기화(Synchronization in Kernel)는 Mutex, Event, Semaphore Object를 사용하며 커널에 의해 공유되기 때문에 다른 프로세스에 존재하는 쓰레드들 간의 동기화가 가능합니다. 또, Deadlock을 방지하기 위해 타임 아웃을 설정할 수 있습니다. 하지만 연산 모드를 변경하기 때문에 유저모드보다 상대적으로 느릴 수 있는 단점이 있습니다.





 Java에서의 스레드 동기화

Java에서는 위의 어려운 개념을 다 익히지 않고도 쉽게 동기화를 할 수 있도록 synchronized를 제공해 주고 있습니다!


1.임계구역

1
2
3
4
5
6
7
        synchronized (java.lang.Object.class) {
            System.out.println("----------Start Working!----------");
            for(int i =0;i<100000000;i++){
            System.out.println(i);
            }
            System.out.println("----------Finish Working!----------");
        }
cs


java.lang.Object는 하나 이므로 위의 코드처럼 java.lang.Object를 기준으로 동기화를 할 수 있습니다. Start Working!이 출력된 뒤 Finish Working!이 출력되어 작업이 끝나기 전까지 다른 스레드들은 작업을 수행하지 않고 기다리게 됩니다.



2.메소드

1
2
3
4
5
6
7
    public synchronized void doWork(){
        System.out.println("----------Start Working!----------");
        for(int i =0;i<100000000;i++){
        System.out.println(i);
        }
        System.out.println("----------Finish Working!----------");
    }
cs


위의 코드는 메소드 자체를 동기화 시키는 코드 입니다. 여러 스레드가 doWork()메소드를 호출하더라도 한번에 한 개의 메소드만 작동되게 됩니다. 위의 경우 인스턴스 메소드이기 때문에 자신의 객체를 기준으로 동기화하고, Static 메소드일 경우 자신의 클래스를 기준으로 동기화하게 됩니다.



 잡담...

쎄트렉아이에 인턴을 다녀온지 첫주가 되었습니다.


첫 회사를 경험해 보니 반성할 점들이 정말 많이 생겼습니다. 그중에 가장 부끄러운 사실은 그동안 오래 써왔던 Java의 스레드 동기화조차도 몰랐던 사실입니다.. 1년 반정도 Java만 다뤄왔지만, 정말 기초가 안되어 있는것 같았습니다.


그래서! 오늘은 Java의 스레드 동기화에 대해서 알아보도록 하겠습니다.


스레드 동기화는 SQLite를 다루다 보니 처음 만나게 되었습니다. SQLite는 제가 그동안 써왔던 mySQL과는 다르게 여러개의 세션 작업이 불가능 했습니다. 헌데 저는 그것도 모르고 여러 스레드에서 무작위로 명령어를 날렸으니.. 그래서 'database id locked'오류가 발생했고, 이게 뭔지 해결하려고 3시간 정도를 날린것 같네요..ㅠㅠ


댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함