동기화/비동기화

Updated:

동기화 / 비동기화

  • 결과를 받는 시점이 다르다는 것이 차이점이다.

  • 호출되는 함수의 작업 완료 여부(callback)를 누가 신경쓰냐가 차이점.

ex) 호출되는 함수(A)에게 callback을 전달. 호출되는 함수(A)가 작업을 마치면 끝났다고 callback을 실행.

이때 호출되는 함수(A)를 호출하는 함수(B)가 작업 완료 여부(callback)를

신경쓰면 동기화(or return 받아도 원하는 결과를 callback 받을 때까지 신경씀)

신경 쓰지 않으면 비동기화.

동기화(synchronized)

  • 요청과 원하는 결과가 동시에 일어남.

  • 요청을 하면 시간이 얼마나 걸리든 원하는 결과(return)을 받아야 함.

  • 가장 쉬운 예 : ATM에서 돈 인출

비동기화 (asynchronized)

  • 요청과 원하는 결과가 동시에 일어나지 않는다.

  • 요청을 하면 응답(return)을 받으나, 내가 원하는 결과(result)를 받지 못할 수 도 있다.

  • 가장 쉬운 예 : 시험날의 학생과 선생

블록킹/논블록킹

  • 호출되는 함수가 바로 리턴하냐 마느냐

호출된 함수가 리턴하지 않아 제어권을 주지 않고 호출한 함수가 대기한다. 블록킹

호출된 함수가 바로 리턴해서 호출한 함수에게 제어권을 넘겨주고, 호출한 함수가 다른일을 할 수 있다. 논블록킹.

  • 블록킹, 논블록킹은 주로 I/O의 읽기, 쓰기에서 사용

블록킹(Blocking)

  • 요청한 작업을 마칠 때가지 계속 대기.

  • Thread 개념 : 요청 작업이 끝날 때까지 계속 대기. 리턴 값 받을 때까지 한 쓰레드를 계속 사용(대기)

논블록킹(Non-Blocking)

  • 요청한 작업을 마칠 수 없으면 그냥 return.

  • Thread 개념 : 하나의 thread가 여러 개의 I/O를 처리

동기, 비동기에서 블록킹, 논블록킹 조합(예제)

상황 조합
호출하는 함수가 응답을 기다리며 다른일을 못함 동기 + 블록킹
호출하는 함수가 응답을 기다리며 다른일을 함 동기 + 논블록킹
호출하는 함수가 응답을 기다리지 않고 다른일을 못함 비동기 + 블록킹
호출하는 함수가 응답을 기다리지 않고 다른일을 함 비동기 + 논블록킹

동기에서 블록킹, 논블록킹

  • 동기 + 블록킹 : 결과가 처리 되어 나올 때까지 기다렸다가 리턴 값에 원하는 결과를 받음

  • 동기 + 논블록킹 : 결과가 처리 되지 않더라도 리턴을 받음. 원하는 결과를 받을 때까지 계속 요청.

ex) 친구한테 연락을 할 경우.

  • 전화를 해서 연락한다. ====> 동기 요청

  • 이메일로 연락한다. 메일을 보냈다는 송신완료(return 값). 그러나 답은 없음(원하는 결과 값) ====> 비동기 요청

  • 전화를 해서 받을 때까지 계속 대기 ====> 동기 + 블록킹

  • 전화 받을 때까지 전화를 계속 걸음. ====> 동기 + 논블록킹

  • 이메일 보냈는데 자동 메일 응답을 받음. ====> 비동기 + 논블록킹

비동기에서 블록킹, 논블록킹

  • 비동기 + 블록킹 : 장점이 없다. 이런 개념은 없다고 보면 된다.

  • 비동기 + 논블록킹 : 결과가 처리 되지 않더라도 리턴을 받음. 그 사이 다른 일을 할 수 있음. 그러나 원하는 결과을 나중에라도 결국 받음.

ex) 시험지 제출에서

  • 학생이 선생에게 시험지 제출 후 결과를 받을 때까지 선생이 반에서 앉아 있으라고 함: 비동기+블록킹

  • 학생이 선생에게 시험지 제출 후 결과를 받을 때까지 선생이 나가서 놀라고 함: 비동기+논블록킹

  • 조금 찾아보니 비동기+블록킹 같은 사례가 있더라…

  • Node.js 쪽에서 callback 지옥을 헤치면서 Async로 전진해와도, 결국 DB 작업 호출 시에는 MySQL에서 제공하는 드라이버를 호출하게 되는데, 이 드라이버가 Blocking 방식이라고 한다.

이건 사실 Node.js 뿐아니라 Java의 JDBC도 마찬가지다. 다만 Node.js가 싱글 쓰레드 루프 기반이라 멀티 쓰레드 기반인 Java의 Servlet 컨테이너보다 문제가 더 두드러져 보일 뿐, Blocking-Async라는 근본 원인은 같다.

  • NonBlocking-Async 방식을 쓰는데 그 과정 중에 하나라도 Blocking으로 동작하는 놈이 포함되어 있다면 의도하지 않게 Blocking-Async로 동작**할 수 있다.

코드 예제

class User {
    private int userNo = 0;
 
    // 임계 영역을 지정하는 synchronized메소드
    public void add(String name) {
        System.out.println(name + " : " + userNo++ + "번째 사용");
    }
}
 
class UserThread extends Thread {
    User user;
 
    UserThread(User user, String name) {
        super(name);
        this.user = user;
    }
 
    public void run() {
        try {
            for (int i = 0; i < 3; i++) {
                user.add(getName());
                sleep(500);
            }
        } catch (InterruptedException e) {
            System.err.println(e.getMessage());
        }
    }
}
 
public class SyncThread {
 
    public static void main(String[] args) {
 
        User user = new User();
 
        // 3개의 스레드 객체 생성
        UserThread p1 = new UserThread(user, "A1");
        UserThread p2 = new UserThread(user, "B2");
        UserThread p3 = new UserThread(user, "C3");
 
        // 스레드 스케줄링 : 우선순위 부여
        p1.setPriority(p1.MAX_PRIORITY);
        p2.setPriority(p2.NORM_PRIORITY);
        p3.setPriority(p3.MIN_PRIORITY);
 
        System.out.println("-----------------------");
        System.out.println("sychronized 적용안한 경우");
        System.out.println("-----------------------");
 
        // 스레드 시작
        p1.start();
        p2.start();
        p3.start();
    }
}
/* 결과는 아래와 상이하게 나올 수 있음. 동기화를 안했기 때문에 
-----------------------
sychronized 적용안한 경우
-----------------------
A1 : 0번째 사용
B2 : 1번째 사용
C3 : 2번째 사용
A1 : 3번째 사용
C3 : 5번째 사용 --이렇게 원하는 순서대로 나오질 않음
B2 : 4번째 사용
C3 : 7번째 사용
A1 : 6번째 사용
B2 : 8번째 사용
*/
class User {
  private int userNo = 0;
    
  // 임계 영역을 지정하는 synchronized메소드
  public synchronized void add(String name) {
		System.out.println(name + " : " + userNo++ + "번째 사용");
  }
}

/* 위와 같이 수정 후 결과가 아래와 같이 깔끔하게 나옴 
-----------------------
sychronized 적용한 경우
-----------------------
A1 : 0번째 사용
C3 : 1번째 사용
B2 : 2번째 사용
A1 : 3번째 사용
B2 : 4번째 사용
C3 : 5번째 사용
A1 : 6번째 사용
B2 : 7번째 사용
C3 : 8번째 사용
*/