본문 바로가기

1.프로그래밍/Java

[Java] Java Synchronized 란? (Java 동기화)

728x90
반응형

[Java] Java Synchronized 란? (Java 동기화)

Synchronized 란?

먼저 Synchronized란 한글로 번역하면 동기화라는 의미를 갖는 단어이다.


Synchronized (동기화)라는 뜻의 사전적 정의는 시스템을 동시에 작동시키기 위해 여러 사건들을 조화시키는 것을 의미한다. 라고 나와있다.


위의 사전적 정의만으로 동기화에 대한 이해가 확실이 되었다면, 이 글을 보지 않을까 싶다.


만일 JavaScript를 다루면서 AJax통신에 대해서 다뤄 보았다면 이해가 더 잘될꺼라 생각된다.

AJax(Asynchronous JavaScript And XML)란 웹의 비동기적 통신을 위한 기술이다.


여기서 비동기적 통신의 의미는 만약, 우리가 웹사이트를 이용할 경우 다양한 기능을 사용할 것이다.
예를 들어, 댓글을 달거나 회원가입 시에 이메일 혹은 문자를 전송할 경우 우리의 웹 페이지는 새로고침이 되지 않는다.


즉, 웹 페이지 전체를 리프레쉬 하지 않고 일부분의 Event만 수행하게 하는 것이 비동기적 통신의 간략한 설명이다.


그렇다면, Synchronized란 간단히 말해 하나의 프로세스가 진행될 때 다른 프로세스가 간섭하지 못하게 해당 프로세스만을 진행하고 수행하도록 하는 것이라고 설명할 수 있다.

이 기능은 하나의 프로세스 연산 중에 다른 프로세스들이 동시에 접근하는 것을 허용하지 않을때 주로 사용된다.

Java Synchronized 사용

java에서 동기화 방식은 메서드 앞에 synchronized를 선언하여 동기화 시키는 방식과, 동기화 블럭을 만들어 동기화를 시키는 방식 총 2가지가 존재한다.

그리고 그 전에 Thread에 대해 이해가 있으면 좋다.


https://myeongdev.tistory.com/74


쓰레드에 대해 열심히 공부하여 정리한 글이 있으니 필요하면 참고하길 바란다.


먼저, Thread에 동기화를 하지 않고 실행하였을 경우이다.


동기화 하지 않은 코드


package thread;

class PrintClass{
    public void print(int n){
        for(int i = 1; i <= 5; i++){
            System.out.println("Current Thread : " + Thread.currentThread().getName() + " value : " + n * i);
            try{
                Thread.sleep(3000);
            } catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

class TestThread extends Thread{
    PrintClass pc;
    int num;

    public TestThread(PrintClass pc, int num){
        this.pc = pc;
        this.num = num;
    }

    @Override
    public void run() {
        pc.print(this.num);
    }
}

public class SynchronizedTest {
    public static void main(String[] args) {
        PrintClass pc = new PrintClass();

        TestThread th1 = new TestThread(pc, 5);
        TestThread th2 = new TestThread(pc, 100);


        th1.start();
        th2.start();

    }    
}
// 출력
/*
Current Thread : Thread-0 value : 5
Current Thread : Thread-1 value : 100
Current Thread : Thread-1 value : 200
Current Thread : Thread-0 value : 10
Current Thread : Thread-1 value : 300
Current Thread : Thread-0 value : 15
Current Thread : Thread-0 value : 20
Current Thread : Thread-1 value : 400
Current Thread : Thread-0 value : 25
Current Thread : Thread-1 value : 500
*/

Thread에 대한 매우 간단한 예제코드이고, 위의 출력을 확인하면 각각 동시에 실행되었음을 확인 할 수 있다.
동기화가 되어있지 않은 코드이기 때문에 각각의 스레드가 동시에 돌아가면서 출력값이 나오는것을 볼 수 있다.


synchronized 메서드 코드

package thread;

class PrintClass{
    synchronized public void print(int n){
        for(int i = 1; i <= 5; i++){
            System.out.println("Current Thread : " + Thread.currentThread().getName() + " value : " + n * i);
            try{
                Thread.sleep(3000);
            } catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

class TestThread extends Thread{
    PrintClass pc;
    int num;

    public TestThread(PrintClass pc, int num){
        this.pc = pc;
        this.num = num;
    }

    @Override
    public void run() {
        pc.print(this.num);
    }
}

public class SynchronizedTest {
    public static void main(String[] args) {
        PrintClass pc = new PrintClass();

        TestThread th1 = new TestThread(pc, 5);
        TestThread th2 = new TestThread(pc, 100);

        th1.start();
        th2.start();

    }    
}
//출력
/*
Current Thread : Thread-0 value : 5
Current Thread : Thread-0 value : 10
Current Thread : Thread-0 value : 15
Current Thread : Thread-0 value : 20
Current Thread : Thread-0 value : 25
Current Thread : Thread-1 value : 100
Current Thread : Thread-1 value : 200
Current Thread : Thread-1 value : 300
Current Thread : Thread-1 value : 400
Current Thread : Thread-1 value : 500
*/

위으 코드를 확인하면 print() 메서드 앞에 synchronized를 선언해주었다.
그로인해 출력을 확인하면 th1과 th2는 동기화 되어 th1이 모두 실행 된 후 th2가 실행되었다.


그렇다면 위의 코드에 th3라는 새로운 객체에 새로운 pc객체를 생성해서 넣으면 어떻게 될까?
아래의 코드를 보면 해당 결과에 대한 답을 얻을 수 있다.


서로 다른 객체 사용


package thread;

class PrintClass{
    synchronized public void print(int n){
        for(int i = 1; i <= 5; i++){
            System.out.println("Current Thread : " + Thread.currentThread().getName() + " value : " + n * i);
            try{
                Thread.sleep(3000);
            } catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

class TestThread extends Thread{
    PrintClass pc;
    int num;

    public TestThread(PrintClass pc, int num){
        this.pc = pc;
        this.num = num;
    }

    @Override
    public void run() {
        pc.print(this.num);
    }
}

public class SynchronizedTest {
    public static void main(String[] args) {
        PrintClass pc = new PrintClass();

        TestThread th1 = new TestThread(pc, 5);
        TestThread th2 = new TestThread(pc, 100);
        TestThread th3 = new TestThread(new PrintClass(), 1);

        th1.start();
        th2.start();
        th3.start();

    }    
}
//출력
/*
Current Thread : Thread-0 value : 5
Current Thread : Thread-2 value : 1
Current Thread : Thread-0 value : 10
Current Thread : Thread-2 value : 2
Current Thread : Thread-0 value : 15
Current Thread : Thread-2 value : 3
Current Thread : Thread-0 value : 20
Current Thread : Thread-2 value : 4
Current Thread : Thread-0 value : 25
Current Thread : Thread-2 value : 5
Current Thread : Thread-1 value : 100
Current Thread : Thread-1 value : 200
Current Thread : Thread-1 value : 300
Current Thread : Thread-1 value : 400
Current Thread : Thread-1 value : 500
*/

위의 결과처럼 th1과 th3는 동기화가 이뤄지지 않는 결과를 볼 수 있다.
즉, 같은 객체에 한하여 synchronized를 메서드 앞에 선언하면 같은 객체 메서드를 호출할 경우
동기화가 진행되고, 다른 객체에 대해서는 동기화가 보장이 되지 않는다는 것을 알 수 있다.


그리고 이제는 Synchronized block을 만들어 동기화 시키는 방식이다


Synchronized block 동기화

package thread;

class PrintClass{
    public void print(int n){

        synchronized(this){
            System.out.println("Synchronized block");
            System.out.println("Current Thread : " + Thread.currentThread().getName());
            System.out.println("이 블럭만 동기화 되었습니다.");

            try{
                Thread.sleep(3000);
            } catch(InterruptedException e){
                e.printStackTrace();
            }
        }

        for(int i = 1; i <= 5; i++){
            System.out.println("Current Thread : " + Thread.currentThread().getName() + " value : " + n * i);
            try{
                Thread.sleep(3000);
            } catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

class TestThread extends Thread{
    PrintClass pc;
    int num;

    public TestThread(PrintClass pc, int num){
        this.pc = pc;
        this.num = num;
    }

    @Override
    public void run() {
        pc.print(this.num);
    }
}

public class SynchronizedTest {
    public static void main(String[] args) {
        PrintClass pc = new PrintClass();

        TestThread th1 = new TestThread(pc, 5);
        TestThread th2 = new TestThread(pc, 100);

        th1.start();
        th2.start();

    }    
}
//출력
/*
Synchronized block
Current Thread : Thread-0
이 블럭만 동기화 되었습니다.
Synchronized block
Current Thread : Thread-1
이 블럭만 동기화 되었습니다.
Current Thread : Thread-0 value : 5
Current Thread : Thread-1 value : 100
Current Thread : Thread-0 value : 10
Current Thread : Thread-1 value : 200
Current Thread : Thread-0 value : 15
Current Thread : Thread-1 value : 300
Current Thread : Thread-0 value : 20
Current Thread : Thread-1 value : 400
Current Thread : Thread-0 value : 25
Current Thread : Thread-1 value : 500
*/

위의 코드를 보면 synchronized this{}라는 블럭을 통해 동기화를 시켜주었다.
그렇기에 해당 블록내의 코드만 동기화 되어 차례대로 진행 되었고,
그 이후의 코드는 동기화 없이 실행되게 된다.


위와 같은 방식은 메서드에 내의 일정한 한 부분만 동기화를 시켜 사용할 때에 유용하게 사용 할 수 있을 것 같다.


이상으로 Java의 Synchronized 에 대하여 알아보았다.

728x90
반응형