반응형
함수 호출 관점에서 동기와 비동기
동기 비동기를 알기 전에 알아두면 좋은 개념
- Caller, Callee
- 함수가 다른 함수를 호출하는 상황에서
Caller : 호출하는 함수
Callee : 호출 당하는 함수
- 함수가 다른 함수를 호출하는 상황에서
- 함수형 인터페이스
- 함수형 프로그래밍을 지원하기 위해 java 8부터 도입
- 1개의 추상 메서드를 갖고 있는 인터페이스
- 함수를 1급 객체로 사용할 수 있다.
- Function, Consumer, Supplier, Runnable.. 등
- 함수형 인터페이스를 구현한 익명 클래스를 람다식으로 변경 가능하다.
functionalInterface
1급객체, 람다, 함수형 인터페이스를 인자로 넘기는 예제
@Slf4j public class FunctionalInterface { public static void main(String[] args) { var consumer = getConsumer(); consumer.accept(1); var consumerAsLambda = getConsumerAsLambda(); consumerAsLambda.accept(1); handleConsumer(consumer); } public static Consumer<Integer> getConsumer() { Consumer<Integer> returnValue = new Consumer<Integer>() { @Override public void accept(Integer integer) { log.info("value in interface : {}", integer); } }; return returnValue; } public static Consumer<Integer> getConsumerAsLambda() { return integer -> log.info("value in lambda : {}", integer); } public static void handleConsumer(Consumer<Integer> consumer) { log.info("handleConsumer"); consumer.accept(1); } }
동기와 비동기의 간단한 코드에서의 비교
A class
@Slf4j
public class A {
public static void main(String[] args) {
log.info("Start main");
// caller가 callee(getResult) 호출
var result = getResult();
// callee가 반환해준 value를 가지고 다음 excute(액션)을 수행
var nextValue = result + 1;
assert nextValue == 1;
log.info("Finish main");
}
private static int getResult() {
log.info("Start getResult");
try {
// 1초 슬립! 메인 함수는 최소한 1초의 시간이 걸린다.
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
var result = 0;
try {
return result;
} finally {
log.info("Finish getResult");
}
}
}
B class
@Slf4j
public class B {
public static void main(String[] args) {
log.info("Start main");
getResult(new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
var nextValue = integer + 1;
assert nextValue == 1;
}
});
log.info("Finish main");
}
public static void getResult(Consumer<Integer> cb) {
log.info("Start getResult");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
var result = 0;
cb.accept(result);
log.info("Finish getResult");
}
}
A , B 클래스의 차이
- A class : main은 getResult의 결과에 관심이 있다.
main은 결과를 이용해서 다음 코드를 실행한다.
우리가 보통 자주 사용하는 동기식 프로그래밍 방법이다. - B class : main은 getResult의 결과에 관심이 없다.
getResult는 결과를 이용해서 함수형 인터페이스를 실행한다
비동기 프로그래밍이다.
- 동기 : caller는 callee의 결과에 관심이 있고,
caller는 그 결과를 이용해서 action을 수행한다. - 비동기 : caller는 callee의 결과에 관심이 없다.
callee는 결과를 이용해서 callback을 수행한다
A,B 모델의 공통점
caller (main) 가 getResult를 호출하고 A모델은 getReuslt가 반환될때까지, B모델은 getResult에서 callback 까지 실행한 후까지 아무런 동작도 수행하지 못한다.
이를 Blocking 이라고 한다.
Blocking
caller가 callee를 호출한 후, callee가 완료되기 전까지 caller가 아무것도 할 수 없다.
제어권을 callee가 가지고 있다.
Non-blocking [C class]
@Slf4j
public class C {
public static void main(String[] args) throws InterruptedException {
log.info("Start main");
var count = 1;
Future<Integer> result = getResult();
// getResult에 대한 작업이 끝났는지 계속 확인한다.
while(!result.isDone()) {
log.info("wating for result, count : {}", count++);
Thread.sleep(100);
}
var nextValue = result.get() +1;
assert nextValue = 1;
log.info("Finish main");
}
public static Future<Integer> getResult() {
// 별도의 스레드 생성
var excutor = Executors.newSingleThreadExecutor();
try {
return excutor.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
log.info("Start getResult");
try {
// 1초동안 sleep -> 1초동안 isDone은 false
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
var result = 0;
try {
return result;
} finally {
log.info("Finish getResult");
}
}
});
} finally {
excutor.shutdown();
}
}
callee를 호출한 후, callee가 완료되지 않더라도 caller는 본인의 일을 할 수 있다.
제어권을 caller가 가지고 있다.
Blocking | Non-blocking | |
---|---|---|
설명 | Callee가 완료될 때까지 대기 | Caller는 기다리지 않고 진행 |
제어 | Callee가 제어권을 가짐 | Caller가 제어권을 가짐 |
스레딩 | 별도의 스레드가 필요X | 별도의 스레드가 필요 |
비동기 Non-blocking [D class]
@Slf4j
public class D {
public static void main(String[] args) {
log.info("Start main");
getResult(new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
var nextValue = integer + 1;
assert nextValue == 1;
}
});
log.info("Finish main");
}
private static void getResult(Consumer<Integer> callbackc) {
// 별도의 스레드로 동작된다.
var excutor = Executors.newSingleThreadExecutor();
try {
excutor.submit(new Runnable() {
@Override
public void run() {
log.info("Start getResult");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
var result = 0;
try {
callbackc.accept(result);
} finally {
log.info("Finish getResult");
}
}
});
} finally {
excutor.shutdown();
}
}
}
- main은 getResult의 결과에 관심이 없다. (비동기)
getResult를 호출한 후, getResult가 완료되지 않더라도 main은 본인의 일을 할 수 있다. (Non-blocking) - D 모델은 비동기 Non-blocking 모델이다.
정리하자면..
반응형
'Reactive-Programming' 카테고리의 다른 글
Project reactor (0) | 2024.04.21 |
---|---|
HotPublisher, ColdPublisher (0) | 2024.04.17 |
Reactive_streams (0) | 2024.04.17 |
Reactive programming (0) | 2024.04.16 |
Reactive manifesto (0) | 2024.04.15 |