├── .gitignore
├── README.md
├── build.gradle.kts
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle.kts
└── src
├── main
└── kotlin
│ ├── section1
│ ├── code1
│ │ └── Code1-1.kt
│ ├── code2
│ │ └── Code1-2.kt
│ ├── code3
│ │ └── Code1-3.kt
│ ├── code4
│ │ └── code1_4.kt
│ ├── code5
│ │ └── code1_5.kt
│ └── code6
│ │ └── Code1-6.kt
│ ├── section10
│ ├── code1
│ │ └── Code10-1.kt
│ ├── code2
│ │ └── Code10-2.kt
│ ├── code3
│ │ └── Code10-3.kt
│ ├── code4
│ │ └── Code10-4.kt
│ ├── code5
│ │ └── Code10-5.kt
│ ├── code6
│ │ └── Code10-6.kt
│ ├── code7
│ │ └── Code10-7.kt
│ └── code8
│ │ └── Code10-8.kt
│ ├── section11
│ ├── code1
│ │ └── Code11-1.kt
│ ├── code10
│ │ └── Code11-10.kt
│ ├── code11
│ │ └── Code11-11.kt
│ ├── code12
│ │ └── Code11-12.kt
│ ├── code13
│ │ └── Code11-13.kt
│ ├── code14
│ │ └── Code11-14.kt
│ ├── code15
│ │ └── Code11-15.kt
│ ├── code16
│ │ └── Code11-16.kt
│ ├── code17
│ │ └── Code11-17.kt
│ ├── code18
│ │ └── Code11-18.kt
│ ├── code19
│ │ └── Code11-19.kt
│ ├── code2
│ │ └── Code11-2.kt
│ ├── code20
│ │ └── Code11-20.kt
│ ├── code21
│ │ └── Code11-21.kt
│ ├── code22
│ │ └── Code11-22.kt
│ ├── code3
│ │ └── Code11-3.kt
│ ├── code4
│ │ └── Code11-4.kt
│ ├── code5
│ │ └── Code11-5.kt
│ ├── code6
│ │ └── Code11-6.kt
│ ├── code7
│ │ └── Code11-7.kt
│ ├── code8
│ │ └── Code11-8.kt
│ └── code9
│ │ └── Code11-9.kt
│ ├── section12
│ ├── code1
│ │ └── AddUseCase.kt
│ ├── code2
│ │ ├── UserNameRepository.kt
│ │ ├── UserPhoneNumberRepository.kt
│ │ ├── UserProfile.kt
│ │ └── UserProfileFetcher.kt
│ ├── code3
│ │ └── RepeatAddUseCase.kt
│ ├── code4
│ │ └── RepeatAddWithDelayUseCase.kt
│ ├── code6
│ │ ├── Follower.kt
│ │ ├── FollowerSearcher.kt
│ │ ├── OfficialAccountRepository.kt
│ │ └── PersonAccountRepository.kt
│ └── code7
│ │ └── StringStateHolder.kt
│ ├── section2
│ ├── code1
│ │ └── Code2-1.kt
│ └── code2
│ │ └── Code2-2.kt
│ ├── section3
│ ├── code1
│ │ └── Code3-1.kt
│ ├── code2
│ │ └── Code3-2.kt
│ ├── code3
│ │ └── Code3-3.kt
│ ├── code4
│ │ └── Code3-4.kt
│ ├── code5
│ │ └── Code3-5.kt
│ ├── code6
│ │ └── Code3-6.kt
│ ├── code7
│ │ └── Code3-7.kt
│ └── code8
│ │ └── Code3-8.kt
│ ├── section4
│ ├── code1
│ │ └── Code4-1.kt
│ ├── code10
│ │ └── Code4-10.kt
│ ├── code11
│ │ └── Code4-11.kt
│ ├── code12
│ │ └── Code4-12.kt
│ ├── code13
│ │ └── Code4-13.kt
│ ├── code14
│ │ └── Code4-14.kt
│ ├── code15
│ │ └── Code4-15.kt
│ ├── code16
│ │ └── Code4-16.kt
│ ├── code17
│ │ └── Code4-17.kt
│ ├── code18
│ │ └── Code4-18.kt
│ ├── code19
│ │ └── Code4-19.kt
│ ├── code2
│ │ └── Code4-2.kt
│ ├── code20
│ │ └── Code4-20.kt
│ ├── code21
│ │ └── Code4-21.kt
│ ├── code22
│ │ └── Code4-22.kt
│ ├── code23
│ │ └── Code4-23.kt
│ ├── code24
│ │ └── Code4-24.kt
│ ├── code25
│ │ └── Code4-25.kt
│ ├── code26
│ │ └── Code4-26.kt
│ ├── code27
│ │ └── Code4-27.kt
│ ├── code3
│ │ └── Code4-3.kt
│ ├── code4
│ │ └── Code4-4.kt
│ ├── code5
│ │ └── Code4-5.kt
│ ├── code6
│ │ └── Code4-6.kt
│ ├── code7
│ │ └── Code4-7.kt
│ ├── code8
│ │ └── Code4-8.kt
│ └── code9
│ │ └── Code4-9.kt
│ ├── section5
│ ├── code1
│ │ └── Code5-1.kt
│ ├── code10
│ │ └── Code5-10.kt
│ ├── code11
│ │ └── Code5-11.kt
│ ├── code12
│ │ └── Code5-12.kt
│ ├── code13
│ │ └── Code5-13.kt
│ ├── code14
│ │ └── Code5-14.kt
│ ├── code15
│ │ └── Code5-15.kt
│ ├── code2
│ │ └── Code5-2.kt
│ ├── code3
│ │ └── Code5-3.kt
│ ├── code4
│ │ └── Code5-4.kt
│ ├── code5
│ │ └── Code5-5.kt
│ ├── code6
│ │ └── Code5-6.kt
│ ├── code7
│ │ └── Code5-7.kt
│ ├── code8
│ │ └── Code5-8.kt
│ └── code9
│ │ └── Code5-9.kt
│ ├── section6
│ ├── code1
│ │ └── Code6-1.kt
│ ├── code10
│ │ └── Code6-10.kt
│ ├── code2
│ │ └── Code6-2.kt
│ ├── code3
│ │ └── Code6-3.kt
│ ├── code4
│ │ └── Code6-4.kt
│ ├── code5
│ │ └── Code6-5.kt
│ ├── code6
│ │ └── Code6-6.kt
│ ├── code7
│ │ └── Code6-7.kt
│ ├── code8
│ │ └── Code6-8.kt
│ └── code9
│ │ └── Code6-9.kt
│ ├── section7
│ ├── code1
│ │ └── Code7-1.kt
│ ├── code10
│ │ └── Code7-10.kt
│ ├── code11
│ │ └── Code7-11.kt
│ ├── code12
│ │ └── Code7-12.kt
│ ├── code13
│ │ └── Code7-13.kt
│ ├── code14
│ │ └── Code7-14.kt
│ ├── code15
│ │ └── Code7-15.kt
│ ├── code16
│ │ └── Code7-16.kt
│ ├── code17
│ │ └── Code7-17.kt
│ ├── code18
│ │ └── Code7-18.kt
│ ├── code19
│ │ └── Code7-19.kt
│ ├── code2
│ │ └── Code7-2.kt
│ ├── code20
│ │ └── Code7-20.kt
│ ├── code21
│ │ └── Code7-21.kt
│ ├── code22
│ │ └── Code7-22.kt
│ ├── code23
│ │ └── Code7-23.kt
│ ├── code24
│ │ └── Code7-24.kt
│ ├── code25
│ │ └── Code7-25.kt
│ ├── code26
│ │ └── Code7-26.kt
│ ├── code27
│ │ └── Code7-27.kt
│ ├── code28
│ │ └── Code7-28.kt
│ ├── code29
│ │ └── Code7-29.kt
│ ├── code3
│ │ └── Code7-3.kt
│ ├── code30
│ │ └── Code7-30.kt
│ ├── code31
│ │ └── Code7-31.kt
│ ├── code32
│ │ └── Code7-32.kt
│ ├── code4
│ │ └── Code7-4.kt
│ ├── code5
│ │ └── Code7-5.kt
│ ├── code6
│ │ └── Code7-6.kt
│ ├── code7
│ │ └── Code7-7.kt
│ ├── code8
│ │ └── Code7-8.kt
│ └── code9
│ │ └── Code7-9.kt
│ ├── section8
│ ├── code1
│ │ └── Code8-1.kt
│ ├── code10
│ │ └── Code8-10.kt
│ ├── code11
│ │ └── Code8-11.kt
│ ├── code12
│ │ └── Code8-12.kt
│ ├── code13
│ │ └── Code8-13.kt
│ ├── code14
│ │ └── Code8-14.kt
│ ├── code15
│ │ └── Code8-15.kt
│ ├── code16
│ │ └── Code8-16.kt
│ ├── code17
│ │ └── Code8-17.kt
│ ├── code18
│ │ └── Code8-18.kt
│ ├── code19
│ │ └── Code8-19.kt
│ ├── code2
│ │ └── Code8-2.kt
│ ├── code3
│ │ └── Code8-3.kt
│ ├── code4
│ │ └── Code8-4.kt
│ ├── code5
│ │ └── Code8-5.kt
│ ├── code6
│ │ └── Code8-6.kt
│ ├── code7
│ │ └── Code8-7.kt
│ ├── code8
│ │ └── Code8-8.kt
│ └── code9
│ │ └── Code8-9.kt
│ └── section9
│ ├── code1
│ └── Code9-1.kt
│ ├── code10
│ └── Code9-10.kt
│ ├── code11
│ └── Code9-11.kt
│ ├── code12
│ └── Code9-12.kt
│ ├── code2
│ └── Code9-2.kt
│ ├── code3
│ └── Code9-3.kt
│ ├── code4
│ └── Code9-4.kt
│ ├── code5
│ └── Code9-5.kt
│ ├── code6
│ └── Code9-6.kt
│ ├── code7
│ └── Code9-7.kt
│ ├── code8
│ └── Code9-8.kt
│ └── code9
│ └── Code9-9.kt
└── test
└── kotlin
└── chapter12
├── code1
├── AddUseCaseTest.kt
└── AddUseCaseTestWithBeforeEach.kt
├── code2
├── FakeUserPhoneNumberRepository.kt
├── StubUserNameRepository.kt
└── UserProfileFetcherTest.kt
├── code3
└── RepeatAddUseCaseTest.kt
├── code4
└── RepeatAddWithDelayUseCaseTest.kt
├── code5
└── TestCoroutineScheduler.kt
├── code6
├── FollowerSearcherTest.kt
├── StubOfficialAccountRepository.kt
└── StubPersonAccountRepository.kt
├── code7
├── StringStateHolderTestFail.kt
└── StringStateHolderTestSuccess.kt
└── code8
└── BackgroundScopeTest.kt
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | build/
3 | !gradle/wrapper/gradle-wrapper.jar
4 | !**/src/main/**/build/
5 | !**/src/test/**/build/
6 |
7 | ### IntelliJ IDEA ###
8 | .idea/modules.xml
9 | .idea/jarRepositories.xml
10 | .idea/compiler.xml
11 | .idea/libraries/
12 | *.iws
13 | *.iml
14 | *.ipr
15 | out/
16 | !**/src/main/**/out/
17 | !**/src/test/**/out/
18 |
19 | ### Eclipse ###
20 | .apt_generated
21 | .classpath
22 | .factorypath
23 | .project
24 | .settings
25 | .springBeans
26 | .sts4-cache
27 | bin/
28 | !**/src/main/**/bin/
29 | !**/src/test/**/bin/
30 |
31 | ### NetBeans ###
32 | /nbproject/private/
33 | /nbbuild/
34 | /dist/
35 | /nbdist/
36 | /.nb-gradle/
37 |
38 | ### VS Code ###
39 | .vscode/
40 |
41 | ### Mac OS ###
42 | .DS_Store
43 | /.idea/
44 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | ## 소개
8 | 『코틀린 코루틴 완전 정복』, 인프런(2024) 강의의 코드를 모아 놓은 저장소 입니다.
9 |
10 |
11 |
12 | ## 코드 실행 방법
13 | ### 예시 코드
14 | 예시 코드는 main 함수 옆의 재생 버튼(►)을 누르고, Run '파일명' 버튼을 누르면 실행 가능합니다.
15 |
16 |
17 |
18 |
19 | ## 링크 목록
20 | - 카카오톡 오픈챗: [코틀린, 안드로이드, 스프링 사용자 모임](https://open.kakao.com/o/gAmC7aVd)
21 |
22 |
23 |
24 | ## 코드 문의 및 오타 신고 ⚠️
25 | - 강사 이메일: seyoungcho2@gmail.com
26 |
27 |
28 |
29 | ## 강의가 유용하다고 생각하셨나요?👍
30 | - 깃허브 스타⭐를 통해 강의를 지지해주세요!
강의을 지지한 사람을 [Stargazers](https://github.com/seyoungcho2/coroutinelecture/stargazers) 페이지에서 볼 수 있습니다.
31 | - 강의가 어땠는지 수강평을 남겨주세요!
32 |
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | kotlin("jvm") version "2.0.0"
3 | }
4 |
5 | group = "info.coroutine"
6 | version = "1.0-SNAPSHOT"
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | dependencies {
13 | // 코루틴 라이브러리
14 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
15 |
16 | // JUnit5 테스트 프레임워크
17 | testImplementation("org.junit.jupiter:junit-jupiter-api:5.11.1")
18 | testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.11.1")
19 |
20 | // 코루틴 테스트 라이브러리
21 | testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1")
22 | }
23 |
24 | tasks.test {
25 | useJUnitPlatform()
26 | }
27 |
28 | kotlin {
29 | jvmToolchain(17)
30 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.code.style=official
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seyoungcho2/coroutinelecture/8ffd548762cd2d3195085116a4707cfad3a41b03/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Jun 25 04:03:57 KST 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Use "xargs" to parse quoted args.
209 | #
210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
211 | #
212 | # In Bash we could simply go:
213 | #
214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
215 | # set -- "${ARGS[@]}" "$@"
216 | #
217 | # but POSIX shell has neither arrays nor command substitution, so instead we
218 | # post-process each arg (as a line of input to sed) to backslash-escape any
219 | # character that might be a shell metacharacter, then use eval to reverse
220 | # that process (while maintaining the separation between arguments), and wrap
221 | # the whole thing up as a single "set" statement.
222 | #
223 | # This will of course break if any of these variables contains a newline or
224 | # an unmatched quote.
225 | #
226 |
227 | eval "set -- $(
228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
229 | xargs -n1 |
230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
231 | tr '\n' ' '
232 | )" '"$@"'
233 |
234 | exec "$JAVACMD" "$@"
235 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
3 | }
4 | rootProject.name = "coroutinelecture"
5 |
6 |
--------------------------------------------------------------------------------
/src/main/kotlin/section1/code1/Code1-1.kt:
--------------------------------------------------------------------------------
1 | package section1.code1
2 |
3 | fun main() {
4 | println("[${Thread.currentThread().name}] 시작")
5 | Thread.sleep(1000L)
6 | println("[${Thread.currentThread().name}] 종료")
7 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section1/code2/Code1-2.kt:
--------------------------------------------------------------------------------
1 | package section1.code2
2 |
3 | class ExampleThread : Thread() {
4 | override fun run() {
5 | println("[${Thread.currentThread().name}] 시작")
6 | Thread.sleep(2000L)
7 | println("[${Thread.currentThread().name}] 종료")
8 | }
9 | }
10 |
11 | fun main() {
12 | println("[${Thread.currentThread().name}] 시작")
13 | ExampleThread().start()
14 | Thread.sleep(1000L)
15 | println("[${Thread.currentThread().name}] 종료")
16 | }
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/main/kotlin/section1/code3/Code1-3.kt:
--------------------------------------------------------------------------------
1 | package section1.code3
2 |
3 | import kotlin.concurrent.thread
4 |
5 | fun main() {
6 | println("[${Thread.currentThread().name}] 시작")
7 | thread {
8 | println("[${Thread.currentThread().name}] 시작")
9 | Thread.sleep(2000L)
10 | println("[${Thread.currentThread().name}] 종료")
11 | }
12 | Thread.sleep(1000L)
13 | println("[${Thread.currentThread().name}] 종료")
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/kotlin/section1/code4/code1_4.kt:
--------------------------------------------------------------------------------
1 | package section1.code4
2 |
3 | import java.util.concurrent.Executors
4 |
5 | fun main() {
6 | // ExecutorService 생성
7 | val executorService = Executors.newFixedThreadPool(2)
8 |
9 | // 작업1 제출
10 | executorService.submit {
11 | println("[${Thread.currentThread().name}] 작업1 시작")
12 | Thread.sleep(1000L) // 1초간 대기
13 | println("[${Thread.currentThread().name}] 작업1 완료")
14 | }
15 |
16 | // 작업2 제출
17 | executorService.submit {
18 | println("[${Thread.currentThread().name}] 작업2 시작")
19 | Thread.sleep(1000L) // 1초간 대기
20 | println("[${Thread.currentThread().name}] 작업2 완료")
21 | }
22 |
23 | // 작업3 제출
24 | executorService.submit {
25 | println("[${Thread.currentThread().name}] 작업3 시작")
26 | Thread.sleep(1000L) // 1초간 대기
27 | println("[${Thread.currentThread().name}] 작업3 완료")
28 | }
29 |
30 | // ExecutorService 종료
31 | executorService.shutdown()
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/kotlin/section1/code5/code1_5.kt:
--------------------------------------------------------------------------------
1 | package section1.code5
2 |
3 | import java.util.concurrent.Executors
4 | import java.util.concurrent.Future
5 |
6 | fun main() {
7 | val executorService = Executors.newFixedThreadPool(2)
8 |
9 | // ExecutorService에 반환 값이 있는 작업 제출
10 | val future: Future = executorService.submit {
11 | Thread.sleep(2000)
12 | return@submit "더미 결과값"
13 | }
14 |
15 | // 반환값이 올때까지 메인 스레드 블로킹
16 | val result = future.get()
17 | println(result)
18 |
19 | executorService.shutdown()
20 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section1/code6/Code1-6.kt:
--------------------------------------------------------------------------------
1 | package section1.code6
2 |
3 | import java.util.concurrent.CompletableFuture
4 | import java.util.concurrent.Executors
5 |
6 | fun main() {
7 | val executorService = Executors.newFixedThreadPool(2)
8 |
9 | // ExecutorService에 반환 값이 있는 작업 제출
10 | val completableFuture = CompletableFuture.supplyAsync(
11 | {
12 | Thread.sleep(2000L)
13 | return@supplyAsync "더미 결과값"
14 | },
15 | executorService
16 | )
17 |
18 | // 콜백 형식으로 결과값 처리
19 | completableFuture.thenAccept { result ->
20 | println("결과:${result}")
21 | }
22 |
23 | executorService.shutdown()
24 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section10/code1/Code10-1.kt:
--------------------------------------------------------------------------------
1 | package section10.code1
2 |
3 |
4 | fun routine() {
5 | routineA() // routineA는 routine의 서브루틴
6 | routineB() // routineB는 routine의 서브루틴
7 | }
8 |
9 | fun routineA() {
10 | routineB() // routineB는 routineA의 서브루틴
11 | }
12 |
13 | fun routineB() {
14 | // 작업 실행
15 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section10/code2/Code10-2.kt:
--------------------------------------------------------------------------------
1 | package section10.code2
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch {
7 | while(true) {
8 | println("자식 코루틴에서 작업 실행 중")
9 | yield() // 스레드 사용 권한 양보
10 | }
11 | }
12 |
13 | while(true) {
14 | println("부모 코루틴에서 작업 실행 중")
15 | yield() // 스레드 사용 권한 양보
16 | }
17 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section10/code3/Code10-3.kt:
--------------------------------------------------------------------------------
1 | package section10.code3
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | repeat(10) { repeatTime ->
8 | launch {
9 | delay(1000L) // 1초 동안 코루틴 일시 중단
10 | println("[${getElapsedTime(startTime)}] 코루틴${repeatTime} 실행 완료")
11 | }
12 | }
13 | }
14 |
15 | fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
16 |
--------------------------------------------------------------------------------
/src/main/kotlin/section10/code4/Code10-4.kt:
--------------------------------------------------------------------------------
1 | package section10.code4
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | repeat(10) { repeatTime ->
8 | launch {
9 | Thread.sleep(1000L) // 1초 동안 스레드 블로킹(코루틴의 스레드 점유 유지)
10 | println("[${getElapsedTime(startTime)}] 코루틴${repeatTime} 실행 완료")
11 | }
12 | }
13 | }
14 |
15 | fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
--------------------------------------------------------------------------------
/src/main/kotlin/section10/code5/Code10-5.kt:
--------------------------------------------------------------------------------
1 | package section10.code5
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val job = launch {
7 | println("1. launch 코루틴 작업이 시작됐습니다")
8 | delay(1000L)
9 | println("2. launch 코루틴 작업이 완료됐습니다")
10 | }
11 | println("3. runBlocking 코루틴이 곧 일시 중단 되고 메인 스레드가 양보됩니다")
12 | job.join()
13 | println("4. runBlocking이 메인 스레드에 보내져 작업이 다시 재개됩니다")
14 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section10/code6/Code10-6.kt:
--------------------------------------------------------------------------------
1 | package section10.code6
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val job = launch {
7 | while (this.isActive) {
8 | println("작업 중")
9 | }
10 | }
11 | delay(100L) // 100밀리초간 일시 중단
12 | job.cancel() // 코루틴 취소
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section10/code7/Code10-7.kt:
--------------------------------------------------------------------------------
1 | package section10.code7
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val dispatcher = newFixedThreadPoolContext(2, "Thread")
7 | launch(dispatcher) {
8 | repeat(5) {
9 | println("[${Thread.currentThread().name}] 코루틴 실행이 일시 중단 됩니다")
10 | delay(100L)
11 | println("[${Thread.currentThread().name}] 코루틴 실행이 재개 됩니다")
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section10/code8/Code10-8.kt:
--------------------------------------------------------------------------------
1 | package section10.code8
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val dispatcher = newFixedThreadPoolContext(2, "Thread")
7 | launch(dispatcher) {
8 | repeat(5) {
9 | println("[${Thread.currentThread().name}] 스레드를 점유한채로 100밀리초간 대기합니다")
10 | Thread.sleep(100L)
11 | println("[${Thread.currentThread().name}] 점유한 스레드에서 마저 실행됩니다")
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code1/Code11-1.kt:
--------------------------------------------------------------------------------
1 | package section11.code1
2 |
3 | import kotlinx.coroutines.*
4 |
5 | var count = 0
6 |
7 | fun main() = runBlocking {
8 | withContext(Dispatchers.Default) {
9 | repeat(10_000) {
10 | launch {
11 | count += 1
12 | }
13 | }
14 | }
15 | println("count = $count")
16 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code10/Code11-10.kt:
--------------------------------------------------------------------------------
1 | package section11.code10
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val job = launch {
7 | println("작업1")
8 | }
9 | job.cancel() // 실행 대기 상태의 코루틴에 취소 요청
10 | println("작업2")
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code11/Code11-11.kt:
--------------------------------------------------------------------------------
1 | package section11.code11
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val job = launch(start = CoroutineStart.ATOMIC) {
7 | println("작업1")
8 | }
9 | job.cancel() // 생성 상태의 코루틴에 취소 요청
10 | println("작업2")
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code12/Code11-12.kt:
--------------------------------------------------------------------------------
1 | package section11.code12
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(start = CoroutineStart.UNDISPATCHED) {
7 | println("작업1")
8 | }
9 | println("작업2")
10 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code13/Code11-13.kt:
--------------------------------------------------------------------------------
1 | package section11.code13
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(start = CoroutineStart.UNDISPATCHED) {
7 | println("일시 중단 전에는 CoroutineDispatcher을 거치지 않고 즉시 실행된다")
8 | delay(100L)
9 | println("일시 중단 후에는 CoroutineDispatcher을 거쳐 실행된다")
10 | }
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code14/Code11-14.kt:
--------------------------------------------------------------------------------
1 | package section11.code14
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking(Dispatchers.IO) {
6 | println("runBlocking 코루틴 실행 스레드: ${Thread.currentThread().name}")
7 | launch(Dispatchers.Unconfined) {
8 | println("launch 코루틴 실행 스레드: ${Thread.currentThread().name}")
9 | }
10 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code15/Code11-15.kt:
--------------------------------------------------------------------------------
1 | package section11.code15
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking(Dispatchers.IO) {
6 | println("runBlocking 코루틴 실행 스레드: ${Thread.currentThread().name}")
7 | launch {
8 | println("launch 코루틴 실행 스레드: ${Thread.currentThread().name}")
9 | }
10 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code16/Code11-16.kt:
--------------------------------------------------------------------------------
1 | package section11.code16
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | println("작업1")
7 | launch(Dispatchers.Unconfined) {
8 | println("작업2")
9 | }
10 | println("작업3")
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code17/Code11-17.kt:
--------------------------------------------------------------------------------
1 | package section11.code17
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | println("작업1")
7 | launch {
8 | println("작업2")
9 | }
10 | println("작업3")
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code18/Code11-18.kt:
--------------------------------------------------------------------------------
1 | package section11.code18
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(Dispatchers.Unconfined) {
7 | println("[Dispatchers.Unconfined] 시작 스레드: ${Thread.currentThread().name}")
8 | delay(100L)
9 | println("[Dispatchers.Unconfined] 재개 스레드: ${Thread.currentThread().name}")
10 | }
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code19/Code11-19.kt:
--------------------------------------------------------------------------------
1 | package section11.code19
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(start = CoroutineStart.UNDISPATCHED) {
7 | println("[CoroutineStart.UNDISPATCHED] 시작 스레드: ${Thread.currentThread().name}")
8 | delay(100L)
9 | println("[CoroutineStart.UNDISPATCHED] 재개 스레드: ${Thread.currentThread().name}")
10 | }
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code2/Code11-2.kt:
--------------------------------------------------------------------------------
1 | package section11.code2
2 |
3 | import kotlinx.coroutines.*
4 |
5 | @Volatile
6 | var count = 0
7 |
8 | fun main() = runBlocking {
9 | withContext(Dispatchers.Default) {
10 | repeat(10_000) {
11 | launch {
12 | count += 1
13 | }
14 | }
15 | }
16 | println("count = $count")
17 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code20/Code11-20.kt:
--------------------------------------------------------------------------------
1 | package section11.code20
2 |
3 | fun main() {
4 | println("[${Thread.currentThread().name}] 작업 시작")
5 | Thread.sleep(1000L)
6 | println("[${Thread.currentThread().name}] 작업 종료")
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code21/Code11-21.kt:
--------------------------------------------------------------------------------
1 | package section11.code21
2 |
3 | import kotlinx.coroutines.*
4 | import kotlin.concurrent.thread
5 | import kotlin.coroutines.resume
6 |
7 | fun main() = runBlocking {
8 | val result = suspendCancellableCoroutine { continuation: CancellableContinuation -> // runBlocking 코루틴 일시 중단 시작
9 | thread { // 새로운 스레드 생성
10 | Thread.sleep(1000L) // 1초간 대기
11 | continuation.resume("실행 결과") // runBlocking 코루틴 재개
12 | }
13 | }
14 | println(result) // 코루틴 재개 시 반환 받은 결과 출력
15 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code22/Code11-22.kt:
--------------------------------------------------------------------------------
1 | package section11.code22
2 |
3 | import kotlinx.coroutines.CancellableContinuation
4 | import kotlinx.coroutines.runBlocking
5 | import kotlinx.coroutines.suspendCancellableCoroutine
6 | import kotlin.coroutines.resume
7 |
8 | fun main() = runBlocking {
9 | val result : Response = executeNetworkCall()
10 | println(result) // 코루틴 재개 시 반환 받은 결과 출력
11 | }
12 |
13 | suspend fun executeNetworkCall(): Response {
14 | return suspendCancellableCoroutine { continuation: CancellableContinuation ->
15 | executeNetworkCallAsync(
16 | onSuccess = {
17 | continuation.resume(Response.Success(it))
18 | },
19 | onFail = {
20 | continuation.resume(Response.Fail(it))
21 | }
22 | )
23 | }
24 | }
25 |
26 | sealed class Response() {
27 | data class Success(val string: String) : Response()
28 | data class Fail(val throwable: Throwable): Response()
29 | }
30 |
31 | fun executeNetworkCallAsync(onSuccess: (String) -> Unit, onFail: (Throwable) -> Unit) {
32 | // 네트워크 요청 실행
33 | onSuccess("네트워크 요청 성공")
34 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code3/Code11-3.kt:
--------------------------------------------------------------------------------
1 | package section11.code3
2 |
3 | import kotlinx.coroutines.*
4 | import kotlinx.coroutines.sync.Mutex
5 |
6 | var count = 0
7 | val mutex = Mutex()
8 |
9 | fun main() = runBlocking {
10 | withContext(Dispatchers.Default) {
11 | repeat(10_000) {
12 | launch {
13 | mutex.lock()
14 | count += 1
15 | mutex.unlock()
16 | }
17 | }
18 | }
19 | println("count = $count")
20 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code4/Code11-4.kt:
--------------------------------------------------------------------------------
1 | package section11.code4
2 |
3 | import kotlinx.coroutines.*
4 | import kotlinx.coroutines.sync.Mutex
5 | import kotlinx.coroutines.sync.withLock
6 |
7 | var count = 0
8 | val mutex = Mutex()
9 |
10 | fun main() = runBlocking {
11 | withContext(Dispatchers.Default) {
12 | repeat(10_000) {
13 | launch {
14 | mutex.withLock {
15 | count += 1
16 | }
17 | }
18 | }
19 | }
20 | println("count = $count")
21 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code5/Code11-5.kt:
--------------------------------------------------------------------------------
1 | package section11.code5
2 |
3 | import kotlinx.coroutines.Dispatchers
4 | import kotlinx.coroutines.launch
5 | import kotlinx.coroutines.runBlocking
6 | import kotlinx.coroutines.withContext
7 | import java.util.concurrent.locks.ReentrantLock
8 |
9 | var count = 0
10 | val reentrantLock = ReentrantLock()
11 |
12 | fun main() = runBlocking {
13 | withContext(Dispatchers.Default) {
14 | repeat(10_000) {
15 | launch {
16 | reentrantLock.lock()
17 | count += 1
18 | reentrantLock.unlock()
19 | }
20 | }
21 | }
22 | println("count = ${count}")
23 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code6/Code11-6.kt:
--------------------------------------------------------------------------------
1 | package section11.code6
2 |
3 | import kotlinx.coroutines.*
4 |
5 | var count = 0
6 | val countChangeDispatcher = newSingleThreadContext("전용 스레드")
7 |
8 | fun main() = runBlocking {
9 | withContext(Dispatchers.Default) {
10 | repeat(10_000) {
11 | launch(countChangeDispatcher) {
12 | count += 1
13 | }
14 | }
15 | }
16 | println("count = $count")
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code7/Code11-7.kt:
--------------------------------------------------------------------------------
1 | package section11.code7
2 |
3 | import kotlinx.coroutines.*
4 | import java.util.concurrent.atomic.AtomicInteger
5 |
6 | var count = AtomicInteger(0)
7 |
8 | fun main() = runBlocking {
9 | withContext(Dispatchers.Default) {
10 | repeat(10_000) {
11 | launch {
12 | count.getAndUpdate { it + 1 }
13 | }
14 | }
15 | }
16 | println("count = $count")
17 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code8/Code11-8.kt:
--------------------------------------------------------------------------------
1 | package section11.code8
2 |
3 | import kotlinx.coroutines.*
4 | import java.util.concurrent.atomic.AtomicInteger
5 |
6 | var count = AtomicInteger(0)
7 |
8 | fun main() = runBlocking {
9 | withContext(Dispatchers.Default) {
10 | repeat(10_000) {
11 | launch {
12 | val currentCount = count.get()
13 | // 위 코드와 아래 코드의 실행 사이에 다른 스레드가 count의 값을 읽거나 변경할 수 있다.
14 | count.set(currentCount + 1)
15 | }
16 | }
17 | }
18 | println("count = $count")
19 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section11/code9/Code11-9.kt:
--------------------------------------------------------------------------------
1 | package section11.code9
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch {
7 | println("작업1")
8 | }
9 | println("작업2")
10 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section12/code1/AddUseCase.kt:
--------------------------------------------------------------------------------
1 | package section12.code1
2 |
3 | class AddUseCase {
4 | fun add(vararg args: Int): Int {
5 | return args.sum()
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/kotlin/section12/code2/UserNameRepository.kt:
--------------------------------------------------------------------------------
1 | package section12.code2
2 |
3 | interface UserNameRepository {
4 | fun saveUserName(id: String, name: String)
5 | fun getNameByUserId(id: String): String
6 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section12/code2/UserPhoneNumberRepository.kt:
--------------------------------------------------------------------------------
1 | package section12.code2
2 |
3 | interface UserPhoneNumberRepository {
4 | fun saveUserPhoneNumber(id: String, phoneNumber: String)
5 | fun getPhoneNumberByUserId(id: String): String
6 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section12/code2/UserProfile.kt:
--------------------------------------------------------------------------------
1 | package section12.code2
2 |
3 | data class UserProfile(
4 | val id: String,
5 | val name: String,
6 | val phoneNumber: String
7 | )
--------------------------------------------------------------------------------
/src/main/kotlin/section12/code2/UserProfileFetcher.kt:
--------------------------------------------------------------------------------
1 | package section12.code2
2 |
3 | class UserProfileFetcher(
4 | private val userNameRepository: UserNameRepository,
5 | private val userPhoneNumberRepository: UserPhoneNumberRepository
6 | ) {
7 | fun getUserProfileById(id: String): UserProfile {
8 | // 유저의 이름을 UserNameRepository로부터 가져오기
9 | val userName = userNameRepository.getNameByUserId(id)
10 | // 유저의 전화번호를 UserPhoneNumberRepository로부터 가져오기
11 | val userPhoneNumber = userPhoneNumberRepository.getPhoneNumberByUserId(id)
12 | return UserProfile(
13 | id = id,
14 | name = userName,
15 | phoneNumber = userPhoneNumber
16 | )
17 | }
18 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section12/code3/RepeatAddUseCase.kt:
--------------------------------------------------------------------------------
1 | package section12.code3
2 |
3 | import kotlinx.coroutines.Dispatchers
4 | import kotlinx.coroutines.withContext
5 |
6 | class RepeatAddUseCase {
7 | suspend fun add(repeatTime: Int): Int = withContext(Dispatchers.Default) {
8 | var result = 0
9 | repeat(repeatTime) {
10 | result += 1
11 | }
12 | return@withContext result
13 | }
14 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section12/code4/RepeatAddWithDelayUseCase.kt:
--------------------------------------------------------------------------------
1 | package section12.code4
2 |
3 | import kotlinx.coroutines.delay
4 |
5 | class RepeatAddWithDelayUseCase {
6 | suspend fun add(repeatTime: Int): Int {
7 | var result = 0
8 | repeat(repeatTime) {
9 | delay(100L)
10 | result += 1
11 | }
12 | return result
13 | }
14 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section12/code6/Follower.kt:
--------------------------------------------------------------------------------
1 | package section12.code6
2 |
3 | sealed class Follower(
4 | open val id: String,
5 | open val name: String
6 | ) {
7 | data class OfficialAccount(
8 | override val id: String,
9 | override val name: String
10 | ) : Follower(id, name)
11 |
12 | data class PersonAccount(
13 | override val id: String,
14 | override val name: String
15 | ) : Follower(id, name)
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/src/main/kotlin/section12/code6/FollowerSearcher.kt:
--------------------------------------------------------------------------------
1 | package section12.code6
2 |
3 | import kotlinx.coroutines.async
4 | import kotlinx.coroutines.coroutineScope
5 |
6 | class FollowerSearcher(
7 | private val officialAccountRepository: OfficialAccountRepository,
8 | private val personAccountRepository: PersonAccountRepository
9 | ) {
10 | suspend fun searchByName(name: String): List = coroutineScope {
11 | val officialAccountsDeferred = async {
12 | officialAccountRepository.searchByName(name)
13 | }
14 | val personAccountsDeferred = async {
15 | personAccountRepository.searchByName(name)
16 | }
17 |
18 | return@coroutineScope listOf(
19 | *officialAccountsDeferred.await(),
20 | *personAccountsDeferred.await()
21 | )
22 | }
23 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section12/code6/OfficialAccountRepository.kt:
--------------------------------------------------------------------------------
1 | package section12.code6
2 |
3 | interface OfficialAccountRepository {
4 | suspend fun searchByName(name: String): Array
5 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section12/code6/PersonAccountRepository.kt:
--------------------------------------------------------------------------------
1 | package section12.code6
2 |
3 | interface PersonAccountRepository {
4 | suspend fun searchByName(name: String): Array
5 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section12/code7/StringStateHolder.kt:
--------------------------------------------------------------------------------
1 | package section12.code7
2 |
3 | import kotlinx.coroutines.*
4 |
5 | /**
6 | * 테스트 불가능한 StringStateHolder 객체
7 | */
8 | //class StringStateHolder {
9 | // private val coroutineScope = CoroutineScope(Dispatchers.IO)
10 | //
11 | // var stringState = ""
12 | // private set
13 | //
14 | // fun updateStringWithDelay(string: String) {
15 | // coroutineScope.launch {
16 | // delay(1000L)
17 | // stringState = string
18 | // }
19 | // }
20 | //}
21 |
22 | /**
23 | * 테스트 가능한 StringStateHolder 객체
24 | */
25 | class StringStateHolder(
26 | private val dispatcher: CoroutineDispatcher = Dispatchers.IO
27 | ) {
28 | private val coroutineScope = CoroutineScope(dispatcher)
29 |
30 | var stringState = ""
31 | private set
32 |
33 | fun updateStringWithDelay(string: String) {
34 | coroutineScope.launch {
35 | delay(1000L)
36 | stringState = string
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section2/code1/Code2-1.kt:
--------------------------------------------------------------------------------
1 | package section2.code1
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | println("[${Thread.currentThread().name}] runBlocking 코루틴 시작")
7 | delay(1000L)
8 | println("[${Thread.currentThread().name}] runBlocking 코루틴 종료")
9 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section2/code2/Code2-2.kt:
--------------------------------------------------------------------------------
1 | package section2.code2
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | println("[${Thread.currentThread().name}] runBlocking 코루틴 시작")
7 | launch {
8 | println("[${Thread.currentThread().name}] launch 코루틴 시작")
9 | delay(500L)
10 | println("[${Thread.currentThread().name}] launch 코루틴 종료")
11 | }
12 | delay(1000L)
13 | println("[${Thread.currentThread().name}] runBlocking 코루틴 종료")
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/kotlin/section3/code1/Code3-1.kt:
--------------------------------------------------------------------------------
1 | package section3.code1
2 |
3 | import kotlinx.coroutines.*
4 |
5 | val singleThreadDispatcher: CoroutineDispatcher =
6 | newSingleThreadContext("SingleThread")
7 |
8 | fun main() = runBlocking {
9 | launch(singleThreadDispatcher) {
10 | println("[${Thread.currentThread().name}] 실행")
11 | }
12 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section3/code2/Code3-2.kt:
--------------------------------------------------------------------------------
1 | package section3.code2
2 |
3 | import kotlinx.coroutines.*
4 |
5 | val multiThreadDispatcher: CoroutineDispatcher =
6 | newFixedThreadPoolContext(2, "MultiThread")
7 |
8 | fun main() = runBlocking {
9 | launch(multiThreadDispatcher) {
10 | println("[${Thread.currentThread().name}] 실행")
11 | }
12 | launch(multiThreadDispatcher) {
13 | println("[${Thread.currentThread().name}] 실행")
14 | }
15 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section3/code3/Code3-3.kt:
--------------------------------------------------------------------------------
1 | package section3.code3
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(Dispatchers.IO) {
7 | println("[${Thread.currentThread().name}] 작업1 실행")
8 | }
9 | launch(Dispatchers.IO) {
10 | println("[${Thread.currentThread().name}] 작업2 실행")
11 | }
12 | launch(Dispatchers.IO) {
13 | println("[${Thread.currentThread().name}] 작업3 실행")
14 | }
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/src/main/kotlin/section3/code4/Code3-4.kt:
--------------------------------------------------------------------------------
1 | package section3.code4
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(Dispatchers.IO) {
7 | launch {
8 | println("[${Thread.currentThread().name}] 작업1 실행")
9 | }
10 | launch {
11 | println("[${Thread.currentThread().name}] 작업2 실행")
12 | }
13 | launch {
14 | println("[${Thread.currentThread().name}] 작업3 실행")
15 | }
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/src/main/kotlin/section3/code5/Code3-5.kt:
--------------------------------------------------------------------------------
1 | package section3.code5
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(Dispatchers.Default) {
7 | launch {
8 | println("[${Thread.currentThread().name}] 작업1 실행")
9 | }
10 | launch {
11 | println("[${Thread.currentThread().name}] 작업2 실행")
12 | }
13 | launch {
14 | println("[${Thread.currentThread().name}] 작업3 실행")
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/kotlin/section3/code6/Code3-6.kt:
--------------------------------------------------------------------------------
1 | package section3.code6
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val imageProcessingDispatcher = Dispatchers.Default.limitedParallelism(2)
7 | repeat(1000) {
8 | launch(imageProcessingDispatcher) {
9 | Thread.sleep(1000L) // 이미지 처리 작업
10 | println("[${Thread.currentThread().name}] 이미지 처리 완료")
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/kotlin/section3/code7/Code3-7.kt:
--------------------------------------------------------------------------------
1 | package section3.code7
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val dedicatedDispatcher = Dispatchers.IO.limitedParallelism(2)
7 | repeat(100) {
8 | launch(dedicatedDispatcher) {
9 | println("[${Thread.currentThread().name}] 중요 작업 실행")
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/kotlin/section3/code8/Code3-8.kt:
--------------------------------------------------------------------------------
1 | package section3.code8
2 |
3 | import kotlinx.coroutines.Dispatchers
4 | import kotlinx.coroutines.launch
5 | import kotlinx.coroutines.runBlocking
6 |
7 | fun main() = runBlocking {
8 | launch(Dispatchers.Main) {
9 | println("[${Thread.currentThread().name}] 작업 실행")
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code1/Code4-1.kt:
--------------------------------------------------------------------------------
1 | package section4.code1
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val job: Job = launch {
7 | println("[${Thread.currentThread().name}] 실행")
8 | }
9 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code10/Code4-10.kt:
--------------------------------------------------------------------------------
1 | package section4.code10
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | val longJob: Job = launch(Dispatchers.Default) {
8 | repeat(10) { repeatTime ->
9 | delay(1000L) // 1000밀리초 대기
10 | println("[${getElapsedTime(startTime)}] 반복횟수 ${repeatTime}")
11 | }
12 | }
13 | delay(2500L) // 2500밀리초 대기
14 | longJob.cancel() // 취소
15 | }
16 |
17 | fun getElapsedTime(startTime: Long): String =
18 | "지난 시간: ${System.currentTimeMillis() - startTime}밀리초"
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code11/Code4-11.kt:
--------------------------------------------------------------------------------
1 | package section4.code11
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val longJob: Job = launch(Dispatchers.Default) {
7 | Thread.sleep(1000L)
8 | println("longJob 코루틴의 동작")
9 | }
10 | longJob.cancel() // longJob 취소 요청
11 | executeAfterJobCancelled() // 취소 후 실행돼야 하는 동작
12 | }
13 |
14 | fun executeAfterJobCancelled() {
15 | println("longJob 코루틴 취소 후 실행돼야 하는 동작")
16 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code12/Code4-12.kt:
--------------------------------------------------------------------------------
1 | package section4.code12
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val longJob: Job = launch(Dispatchers.Default) {
7 | Thread.sleep(1000L)
8 | println("longJob 코루틴의 동작")
9 | }
10 | longJob.cancelAndJoin() // longJob 취소 요청 후 취소 완료될 때까지 호출 코루틴 일시 중단
11 | executeAfterJobCancelled() // 취소 후 실행돼야 하는 동작
12 | }
13 |
14 | fun executeAfterJobCancelled() {
15 | println("longJob 코루틴 취소 후 실행돼야 하는 동작")
16 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code13/Code4-13.kt:
--------------------------------------------------------------------------------
1 | package section4.code13
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val longJob: Job = launch(Dispatchers.Default) {
7 | delay(1000L)
8 | println("longJob 코루틴의 동작")
9 | }
10 | longJob.cancelAndJoin() // longJob 취소 요청 후 취소 완료될 때까지 호출 코루틴 일시 중단
11 | executeAfterJobCancelled() // 취소 후 실행돼야 하는 동작
12 | }
13 |
14 | fun executeAfterJobCancelled() {
15 | println("longJob 코루틴 취소 후 실행돼야 하는 동작")
16 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code14/Code4-14.kt:
--------------------------------------------------------------------------------
1 | package section4.code14
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val whileJob: Job = launch(Dispatchers.Default) {
7 | while(true) {
8 | println("작업 중")
9 | }
10 | }
11 | delay(100L) // 100밀리초 대기
12 | whileJob.cancel() // 코루틴 취소
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code15/Code4-15.kt:
--------------------------------------------------------------------------------
1 | package section4.code15
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val whileJob: Job = launch(Dispatchers.Default) {
7 | while(true) {
8 | println("작업 중")
9 | delay(1L)
10 | }
11 | }
12 | delay(100L)
13 | whileJob.cancel()
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code16/Code4-16.kt:
--------------------------------------------------------------------------------
1 | package section4.code16
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val whileJob: Job = launch(Dispatchers.Default) {
7 | while(true) {
8 | println("작업 중")
9 | yield()
10 | }
11 | }
12 | delay(100L)
13 | whileJob.cancel()
14 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code17/Code4-17.kt:
--------------------------------------------------------------------------------
1 | package section4.code17
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val whileJob: Job = launch(Dispatchers.Default) {
7 | while(this.isActive) {
8 | println("작업 중")
9 | }
10 | }
11 | delay(100L)
12 | whileJob.cancel()
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code18/Code4-18.kt:
--------------------------------------------------------------------------------
1 | package section4.code18
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val job: Job = launch {
7 | delay(1000L)
8 | }
9 | println(job)
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code19/Code4-19.kt:
--------------------------------------------------------------------------------
1 | package section4.code19
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val job: Job = launch(start = CoroutineStart.LAZY) {
7 | delay(1000L)
8 | }
9 | println(job)
10 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code2/Code4-2.kt:
--------------------------------------------------------------------------------
1 | package section4.code2
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val updateTokenJob = launch(Dispatchers.IO) {
7 | println("[${Thread.currentThread().name}] 토큰 업데이트 시작")
8 | delay(100L) // 새로운 토큰을 가져오는데 걸리는 시간
9 | println("[${Thread.currentThread().name}] 토큰 업데이트 완료")
10 | }
11 |
12 | val networkCallJob = launch(Dispatchers.IO) {
13 | println("[${Thread.currentThread().name}] 네트워크 요청")
14 | }
15 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code20/Code4-20.kt:
--------------------------------------------------------------------------------
1 | package section4.code20
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val job: Job = launch {
7 | delay(1000L)
8 | }
9 | job.join() // launch 코루틴이 실행 완료될때까지 일시 중단
10 | println(job)
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code21/Code4-21.kt:
--------------------------------------------------------------------------------
1 | package section4.code21
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val whileJob: Job = launch(Dispatchers.IO) {
7 | while(true){
8 | // 작업 실행
9 | }
10 | }
11 | whileJob.cancel() // 코루틴 취소 요청
12 | println(whileJob)
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code22/Code4-22.kt:
--------------------------------------------------------------------------------
1 | package section4.code22
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val whileJob: Job = launch(Dispatchers.IO) {
7 | while(true){
8 | yield() // 스레드 양보(일시 중단)
9 | }
10 | }
11 | whileJob.cancelAndJoin() // 코루틴 취소 완료될때까지 대기
12 | println(whileJob)
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code23/Code4-23.kt:
--------------------------------------------------------------------------------
1 | package section4.code23
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val job: Job = launch(start = CoroutineStart.LAZY) {
7 | delay(1000L)
8 | }
9 | println(job)
10 | printJobState(job)
11 | }
12 |
13 | private fun printJobState(job: Job) {
14 | println(
15 | "Job State\n" +
16 | "isActive >> ${job.isActive}\n" +
17 | "isCancelled >> ${job.isCancelled}\n" +
18 | "isCompleted >> ${job.isCompleted} "
19 | )
20 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code24/Code4-24.kt:
--------------------------------------------------------------------------------
1 | package section4.code24
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val job: Job = launch {
7 | delay(1000L)
8 | }
9 | println(job)
10 | printJobState(job)
11 | }
12 |
13 | private fun printJobState(job: Job) {
14 | println(
15 | "Job State\n" +
16 | "isActive >> ${job.isActive}\n" +
17 | "isCancelled >> ${job.isCancelled}\n" +
18 | "isCompleted >> ${job.isCompleted} "
19 | )
20 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code25/Code4-25.kt:
--------------------------------------------------------------------------------
1 | package section4.code25
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val job: Job = launch {
7 | delay(1000L)
8 | }
9 | job.join() // launch 코루틴이 실행 완료될때까지 일시 중단
10 | println(job)
11 | printJobState(job)
12 | }
13 |
14 |
15 | private fun printJobState(job: Job) {
16 | println(
17 | "Job State\n" +
18 | "isActive >> ${job.isActive}\n" +
19 | "isCancelled >> ${job.isCancelled}\n" +
20 | "isCompleted >> ${job.isCompleted} "
21 | )
22 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code26/Code4-26.kt:
--------------------------------------------------------------------------------
1 | package section4.code26
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val whileJob: Job = launch(Dispatchers.IO) {
7 | while(true){
8 | // 작업 실행
9 | }
10 | }
11 | whileJob.cancel() // 코루틴 취소 요청
12 | println(whileJob)
13 | printJobState(whileJob)
14 | }
15 |
16 | private fun printJobState(job: Job) {
17 | println(
18 | "Job State\n" +
19 | "isActive >> ${job.isActive}\n" +
20 | "isCancelled >> ${job.isCancelled}\n" +
21 | "isCompleted >> ${job.isCompleted} "
22 | )
23 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code27/Code4-27.kt:
--------------------------------------------------------------------------------
1 | package section4.code27
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val whileJob: Job = launch(Dispatchers.IO) {
7 | while(true){
8 | yield() // 스레드 양보(일시 중단)
9 | }
10 | }
11 | whileJob.cancelAndJoin() // 코루틴 취소 완료될때까지 대기
12 | println(whileJob)
13 | printJobState(whileJob)
14 | }
15 |
16 | private fun printJobState(job: Job) {
17 | println(
18 | "Job State\n" +
19 | "isActive >> ${job.isActive}\n" +
20 | "isCancelled >> ${job.isCancelled}\n" +
21 | "isCompleted >> ${job.isCompleted} "
22 | )
23 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code3/Code4-3.kt:
--------------------------------------------------------------------------------
1 | package section4.code3
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val updateTokenJob = launch(Dispatchers.IO) {
7 | println("[${Thread.currentThread().name}] 토큰 업데이트 시작")
8 | delay(100L)
9 | println("[${Thread.currentThread().name}] 토큰 업데이트 완료")
10 | }
11 | updateTokenJob.join() // networkCallJob 실행 전 updateTokenJob.join() 호출
12 |
13 | val networkCallJob = launch(Dispatchers.IO) {
14 | println("[${Thread.currentThread().name}] 네트워크 요청")
15 | }
16 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code4/Code4-4.kt:
--------------------------------------------------------------------------------
1 | package section4.code4
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val convertImageJob1: Job = launch(Dispatchers.Default) {
7 | Thread.sleep(1000L) // 이미지1 변환 작업 실행
8 | println("[${Thread.currentThread().name}] 이미지1 변환 완료")
9 | }
10 | val convertImageJob2: Job = launch(Dispatchers.Default) {
11 | Thread.sleep(1000L) // 이미지2 변환 작업 실행
12 | println("[${Thread.currentThread().name}] 이미지2 변환 완료")
13 | }
14 |
15 | convertImageJob1.join() // 이미지 1이 변환될 때까지 대기
16 | convertImageJob2.join() // 이미지 2가 변환될 때까지 대기
17 |
18 | val uploadImageJob: Job = launch(Dispatchers.IO) {
19 | println("[${Thread.currentThread().name}] 이미지1,2 업로드")
20 | }
21 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code5/Code4-5.kt:
--------------------------------------------------------------------------------
1 | package section4.code5
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val convertImageJob1: Job = launch(Dispatchers.Default) {
7 | Thread.sleep(1000L) // 이미지1 변환 작업 실행
8 | println("[${Thread.currentThread().name}] 이미지1 변환 완료")
9 | }
10 | val convertImageJob2: Job = launch(Dispatchers.Default) {
11 | Thread.sleep(1000L) // 이미지2 변환 작업 실행
12 | println("[${Thread.currentThread().name}] 이미지2 변환 완료")
13 | }
14 |
15 | joinAll(convertImageJob1, convertImageJob2) // 이미지 1,2가 모두 변환될 때까지 대기
16 |
17 | listOf(convertImageJob1, convertImageJob2).joinAll()
18 |
19 | val uploadImageJob: Job = launch(Dispatchers.IO) {
20 | println("[${Thread.currentThread().name}] 이미지1,2 업로드")
21 | }
22 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code6/Code4-6.kt:
--------------------------------------------------------------------------------
1 | package section4.code6
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | val immediateJob: Job = launch {
8 | println("[${getElapsedTime(startTime)}] launch 코루틴 실행")
9 | }
10 | }
11 |
12 | fun getElapsedTime(startTime: Long): String =
13 | "지난 시간: ${System.currentTimeMillis() - startTime}밀리초"
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code7/Code4-7.kt:
--------------------------------------------------------------------------------
1 | package section4.code7
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | val lazyJob: Job = launch(start = CoroutineStart.LAZY) {
8 | println("[${getElapsedTime(startTime)}] launch 코루틴 지연 실행")
9 | }
10 | }
11 |
12 | private fun getElapsedTime(startTime: Long): String =
13 | "지난 시간: ${System.currentTimeMillis() - startTime}밀리초"
14 |
15 |
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code8/Code4-8.kt:
--------------------------------------------------------------------------------
1 | package section4.code8
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | val lazyJob: Job = launch(start = CoroutineStart.LAZY) {
8 | println("[${getElapsedTime(startTime)}] launch 코루틴 지연 실행")
9 | }
10 | delay(3000L) // 3000밀리초간 대기
11 | lazyJob.start() // 코루틴 실행 lazyJob.join()을 호출해도 실행됨
12 | }
13 |
14 |
15 | fun getElapsedTime(startTime: Long): String =
16 | "지난 시간: ${System.currentTimeMillis() - startTime}밀리초"
--------------------------------------------------------------------------------
/src/main/kotlin/section4/code9/Code4-9.kt:
--------------------------------------------------------------------------------
1 | package section4.code9
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | val longJob: Job = launch(Dispatchers.Default) {
8 | repeat(10) { repeatTime ->
9 | delay(1000L) // 1000밀리초 대기
10 | println("[${getElapsedTime(startTime)}] 반복횟수 ${repeatTime}")
11 | }
12 | }
13 | }
14 |
15 | fun getElapsedTime(startTime: Long): String =
16 | "지난 시간: ${System.currentTimeMillis() - startTime}밀리초"
--------------------------------------------------------------------------------
/src/main/kotlin/section5/code1/Code5-1.kt:
--------------------------------------------------------------------------------
1 | package section5.code1
2 | import kotlinx.coroutines.*
3 |
4 | fun main() = runBlocking {
5 | val networkDeferred = async(Dispatchers.IO) {
6 | delay(1000L) // 네트워크 요청
7 | return@async "Dummy Response" // Dummy Response 반환
8 | }
9 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section5/code10/Code5-10.kt:
--------------------------------------------------------------------------------
1 | package section5.code10
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis() // 1. 시작 시간 기록
7 |
8 | // 2. 플랫폼1에서 등록한 관람객 목록을 가져오는 코루틴 실행
9 | val participantDeferred1: Deferred> = async(Dispatchers.IO) {
10 | delay(1000L)
11 | return@async arrayOf("철수", "영수")
12 | }
13 |
14 | // 3. 플랫폼2에서 등록한 관람객 목록을 가져오는 코루틴 실행
15 | val participantDeferred2: Deferred> = async(Dispatchers.IO) {
16 | delay(1000L)
17 | return@async arrayOf("영희")
18 | }
19 |
20 | // 4. 두 개의 코루틴으로부터 결과가 수신될 때까지 대기
21 | val results = listOf(participantDeferred1, participantDeferred2).awaitAll()
22 |
23 | // 5. 지난 시간 표시 및 참여자 목록을 병합해 출력
24 | println("[${getElapsedTime(startTime)}] 참여자 목록: ${listOf(*results[0], *results[1])}")
25 | }
26 |
27 | private fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
--------------------------------------------------------------------------------
/src/main/kotlin/section5/code11/Code5-11.kt:
--------------------------------------------------------------------------------
1 | package section5.code11
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val result: String = withContext(Dispatchers.IO) {
7 | delay(1000L) // 네트워크 요청
8 | println("[${Thread.currentThread().name}] 결과값이 반환됩니다")
9 | return@withContext "결과값" // 결과값 반환
10 | }
11 | println("[${Thread.currentThread().name}] $result") // 결과값 출력
12 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section5/code12/Code5-12.kt:
--------------------------------------------------------------------------------
1 | package section5.code12
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val result: String = async(Dispatchers.IO) {
7 | delay(1000L) // 네트워크 요청
8 | println("[${Thread.currentThread().name}] 결과값이 반환됩니다")
9 | "결과값" // 결과값 반환
10 | }.await()
11 | println("[${Thread.currentThread().name}] $result") // 결과값 출력
12 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section5/code13/Code5-13.kt:
--------------------------------------------------------------------------------
1 | package section5.code13
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val result1: String = withContext(Dispatchers.IO) {
7 | delay(1000L) // 네트워크 요청
8 | "결과값1" // 결과값 반환
9 | }
10 | val result2: String = withContext(Dispatchers.IO) {
11 | delay(1000L) // 네트워크 요청
12 | "결과값1" // 결과값 반환
13 | }
14 |
15 | val results = listOf(result1, result2)
16 | println("[${Thread.currentThread().name}] ${results.joinToString(", ")}") // 결과값 출력
17 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section5/code14/Code5-14.kt:
--------------------------------------------------------------------------------
1 | package section5.code14
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val networkDeferred1: Deferred = async(Dispatchers.IO) {
7 | delay(1000L) // 네트워크 요청
8 | "결과값1" // 결과값 반환
9 | }
10 | val networkDeferred2: Deferred = async(Dispatchers.IO) {
11 | delay(1000L) // 네트워크 요청
12 | "결과값2" // 결과값 반환
13 | }
14 |
15 | val results: List = awaitAll(networkDeferred1, networkDeferred2)
16 | println("[${Thread.currentThread().name}] ${results.joinToString(", ")}") // 결과값 출력
17 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section5/code15/Code5-15.kt:
--------------------------------------------------------------------------------
1 | package section5.code15
2 |
3 | import kotlinx.coroutines.*
4 |
5 | private val myDispatcher1 = newSingleThreadContext("MyThread1")
6 | private val myDispatcher2 = newSingleThreadContext("MyThread2")
7 |
8 | fun main() = runBlocking {
9 | println("[${Thread.currentThread().name}] 코루틴 실행1")
10 | withContext(myDispatcher1) {
11 | println("[${Thread.currentThread().name}] 코루틴 실행2")
12 | withContext(myDispatcher2) {
13 | println("[${Thread.currentThread().name}] 코루틴 실행3")
14 | }
15 | println("[${Thread.currentThread().name}] 코루틴 실행4")
16 | }
17 | println("[${Thread.currentThread().name}] 코루틴 실행5")
18 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section5/code2/Code5-2.kt:
--------------------------------------------------------------------------------
1 | package section5.code2
2 | import kotlinx.coroutines.*
3 |
4 | fun main() = runBlocking {
5 | val networkDeferred: Deferred = async(Dispatchers.IO) {
6 | delay(1000L) // 네트워크 요청
7 | return@async "Dummy Response" // Dummy Response 반환
8 | }
9 | val result = networkDeferred.await() // 결과값이 반환될 때까지 runBlocking 일시 중단
10 | println(result) // 결과값 출력
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section5/code3/Code5-3.kt:
--------------------------------------------------------------------------------
1 | package section5.code3
2 | import kotlinx.coroutines.*
3 |
4 | fun main() = runBlocking {
5 | val networkDeferred: Deferred = async(Dispatchers.IO) {
6 | delay(1000L) // 네트워크 요청
7 | return@async "Dummy Response" // 결과값 반환
8 | }
9 | val result = networkDeferred.await() // networkDeferred로부터 결과값이 반환될 때까지 runBlocking 일시 중단
10 | println(result) // Dummy Response 출력
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section5/code4/Code5-4.kt:
--------------------------------------------------------------------------------
1 | package section5.code4
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val networkDeferred: Deferred = async(Dispatchers.IO) {
7 | delay(1000L)
8 | return@async "Dummy Response"
9 | }
10 | networkDeferred.join() // networkDeferred가 완료될 때까지 runBlocking 일시 중단
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section5/code5/Code5-5.kt:
--------------------------------------------------------------------------------
1 | package section5.code5
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val networkDeferred: Deferred = async(Dispatchers.IO) {
7 | delay(1000L)
8 | return@async "Dummy Response"
9 | }
10 | networkDeferred.cancel() // networkDeferred 코루틴 취소 요청
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section5/code6/Code5-6.kt:
--------------------------------------------------------------------------------
1 | package section5.code6
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val networkDeferred: Deferred = async(Dispatchers.IO) {
7 | delay(1000L)
8 | return@async "Dummy Response"
9 | }
10 | networkDeferred.join()
11 | printJobState(job = networkDeferred)
12 | }
13 |
14 | private fun printJobState(job: Job) {
15 | println(
16 | "Job State\n" +
17 | "isActive >> ${job.isActive}\n" +
18 | "isCancelled >> ${job.isCancelled}\n" +
19 | "isCompleted >> ${job.isCompleted} "
20 | )
21 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section5/code7/Code5-7.kt:
--------------------------------------------------------------------------------
1 | package section5.code7
2 | import kotlinx.coroutines.*
3 |
4 | fun main() = runBlocking {
5 | val startTime = System.currentTimeMillis() // 1. 시작 시간 기록
6 |
7 | // 2. 플랫폼1에서 등록한 관람객 목록을 가져오는 코루틴 실행
8 | val participantDeferred1: Deferred> = async(Dispatchers.IO) {
9 | delay(1000L)
10 | return@async arrayOf("철수","영수")
11 | }
12 | val participants1 = participantDeferred1.await() // 3. 결과가 수신 될 때까지 대기
13 |
14 | // 4. 플랫폼2에서 등록한 관람객 목록을 가져오는 코루틴 실행
15 | val participantDeferred2: Deferred> = async(Dispatchers.IO) {
16 | delay(1000L)
17 | return@async arrayOf("영희")
18 | }
19 | val participants2 = participantDeferred2.await() // 5. 결과가 수신 될 때까지 대기
20 |
21 | // 6. 지난 시간 표시 및 참여자 목록을 병합해 출력
22 | println("[${getElapsedTime(startTime)}] 참여자 목록: ${listOf(*participants1, *participants2)}")
23 | }
24 |
25 | fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
26 |
--------------------------------------------------------------------------------
/src/main/kotlin/section5/code8/Code5-8.kt:
--------------------------------------------------------------------------------
1 | package section5.code8
2 | import kotlinx.coroutines.*
3 |
4 | fun main() = runBlocking {
5 | val startTime = System.currentTimeMillis() // 1. 시작 시간 기록
6 |
7 | // 2. 플랫폼1에서 등록한 관람객 목록을 가져오는 코루틴 실행
8 | val participantDeferred1: Deferred> = async(Dispatchers.IO) {
9 | delay(1000L)
10 | return@async arrayOf("철수","영수")
11 | }
12 |
13 | // 3. 플랫폼2에서 등록한 관람객 목록을 가져오는 코루틴 실행
14 | val participantDeferred2: Deferred> = async(Dispatchers.IO) {
15 | delay(1000L)
16 | return@async arrayOf("영희")
17 | }
18 |
19 | val participants1 = participantDeferred1.await() // 4. 결과가 수신 될 때까지 대기
20 | val participants2 = participantDeferred2.await() // 5. 결과가 수신 될 때까지 대기
21 |
22 | // 6. 지난 시간 표시 및 참여자 목록을 병합해 출력
23 | println("[${getElapsedTime(startTime)}] 참여자 목록: ${listOf(*participants1, *participants2)}")
24 | }
25 |
26 | private fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
27 |
--------------------------------------------------------------------------------
/src/main/kotlin/section5/code9/Code5-9.kt:
--------------------------------------------------------------------------------
1 | package section5.code9
2 |
3 | import kotlinx.coroutines.*
4 |
5 |
6 | fun main() = runBlocking {
7 | val startTime = System.currentTimeMillis() // 1. 시작 시간 기록
8 |
9 | // 2. 플랫폼1에서 등록한 관람객 목록을 가져오는 코루틴 실행
10 | val participantDeferred1: Deferred> = async(Dispatchers.IO) {
11 | delay(1000L)
12 | return@async arrayOf("철수", "영수")
13 | }
14 |
15 | // 3. 플랫폼2에서 등록한 관람객 목록을 가져오는 코루틴 실행
16 | val participantDeferred2: Deferred> = async(Dispatchers.IO) {
17 | delay(1000L)
18 | return@async arrayOf("영희")
19 | }
20 |
21 | // 4. 두 개의 코루틴으로부터 결과가 수신될 때까지 대기
22 | val results = awaitAll(participantDeferred1, participantDeferred2)
23 |
24 | // 5. 지난 시간 표시 및 참여자 목록을 병합해 출력
25 | println("[${getElapsedTime(startTime)}] 참여자 목록: ${listOf(*results[0], *results[1])}")
26 | }
27 |
28 | private fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
29 |
--------------------------------------------------------------------------------
/src/main/kotlin/section6/code1/Code6-1.kt:
--------------------------------------------------------------------------------
1 | package section6.code1
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val coroutineName: CoroutineName = CoroutineName("코루틴 이름 설정")
7 | val dispatcher: CoroutineDispatcher = Dispatchers.IO
8 | val job: Job = Job()
9 | val coroutineExceptionHandler: CoroutineExceptionHandler = CoroutineExceptionHandler(
10 | handler = { coroutineContext, throwable ->
11 | // 예외 처리
12 | }
13 | )
14 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section6/code10/Code6-10.kt:
--------------------------------------------------------------------------------
1 | package section6.code10
2 |
3 | import kotlinx.coroutines.*
4 | import kotlin.coroutines.CoroutineContext
5 |
6 | fun main() = runBlocking {
7 | val coroutineName = CoroutineName("MyCoroutine")
8 | val dispatcher = Dispatchers.IO
9 | val job = Job()
10 | val coroutineContext: CoroutineContext = coroutineName + dispatcher + job
11 |
12 | val deletedCoroutineContext = coroutineContext.minusKey(CoroutineName)
13 |
14 | println("coroutineContext: $coroutineContext")
15 | println("deletedCoroutineContext: $deletedCoroutineContext")
16 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section6/code2/Code6-2.kt:
--------------------------------------------------------------------------------
1 | package section6.code2
2 |
3 | import kotlinx.coroutines.*
4 |
5 | @OptIn(DelicateCoroutinesApi::class, ExperimentalCoroutinesApi::class)
6 | fun main() = runBlocking {
7 | val coroutineContext = newSingleThreadContext("MyThread") + CoroutineName("MyCoroutine")
8 |
9 | launch(context = coroutineContext) {
10 | println("[${Thread.currentThread().name}] 실행")
11 | }
12 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section6/code3/Code6-3.kt:
--------------------------------------------------------------------------------
1 | package section6.code3
2 |
3 | import kotlinx.coroutines.*
4 |
5 | @OptIn(DelicateCoroutinesApi::class, ExperimentalCoroutinesApi::class)
6 | fun main() = runBlocking {
7 | val coroutineContext = newSingleThreadContext("MyThread") + CoroutineName("MyCoroutine")
8 | val newCoroutineContext = coroutineContext + CoroutineName("NewCoroutine")
9 |
10 | launch(context = newCoroutineContext) {
11 | println("[${Thread.currentThread().name}] 실행")
12 | }
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section6/code4/Code6-4.kt:
--------------------------------------------------------------------------------
1 | package section6.code4
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val coroutineContext1 = CoroutineName("MyCoroutine1") + newSingleThreadContext("MyThread1")
7 | val coroutineContext2 = CoroutineName("MyCoroutine2") + newSingleThreadContext("MyThread2")
8 | val combinedCoroutineContext = coroutineContext1 + coroutineContext2
9 |
10 | launch(context = combinedCoroutineContext) {
11 | println("[${Thread.currentThread().name}] 실행")
12 | }
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section6/code5/Code6-5.kt:
--------------------------------------------------------------------------------
1 | package section6.code5
2 |
3 | import kotlinx.coroutines.*
4 | import kotlin.coroutines.CoroutineContext
5 |
6 | val myJob = Job()
7 | val coroutineContext: CoroutineContext = Dispatchers.Default + myJob
8 |
--------------------------------------------------------------------------------
/src/main/kotlin/section6/code6/Code6-6.kt:
--------------------------------------------------------------------------------
1 | package section6.code6
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val coroutineContext = CoroutineName("MyCoroutine") + Dispatchers.IO
7 | val nameFromContext = coroutineContext[CoroutineName.Key]
8 | println(nameFromContext)
9 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section6/code7/Code6-7.kt:
--------------------------------------------------------------------------------
1 | package section6.code7
2 |
3 | import kotlinx.coroutines.*
4 |
5 | @OptIn(ExperimentalStdlibApi::class)
6 | fun main() = runBlocking {
7 | val coroutineContext = CoroutineName("MyCoroutine") + Dispatchers.IO
8 | val nameFromContext = coroutineContext[CoroutineDispatcher] // '.Key'제거
9 | println(nameFromContext)
10 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section6/code8/Code6-8.kt:
--------------------------------------------------------------------------------
1 | package section6.code8
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val coroutineName : CoroutineName = CoroutineName("MyCoroutine")
7 | val dispatcher : CoroutineDispatcher = Dispatchers.IO
8 | val coroutineContext = coroutineName + dispatcher
9 |
10 | println(coroutineContext[coroutineName.key])
11 | println(coroutineContext[dispatcher.key])
12 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section6/code9/Code6-9.kt:
--------------------------------------------------------------------------------
1 | package section6.code9
2 |
3 | import kotlinx.coroutines.*
4 | import kotlin.coroutines.CoroutineContext
5 |
6 | fun main() = runBlocking {
7 | val coroutineName = CoroutineName("MyCoroutine")
8 | val dispatcher = Dispatchers.IO
9 | val myJob = Job()
10 | val coroutineContext: CoroutineContext = coroutineName + dispatcher + myJob
11 |
12 | val deletedCoroutineContext = coroutineContext.minusKey(CoroutineName)
13 |
14 | println(deletedCoroutineContext)
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code1/Code7-1.kt:
--------------------------------------------------------------------------------
1 | package section7.code1
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch { // 부모 코루틴
7 | println("부모 코루틴 실행")
8 | launch { // 자식 코루틴
9 | println("자식 코루틴 실행")
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code10/Code7-10.kt:
--------------------------------------------------------------------------------
1 | package section7.code10
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | val parentJob = launch { // 부모 코루틴 생성
8 | launch { // 자식 코루틴 생성
9 | delay(1000L) // 1초간 대기
10 | println("[${getElapsedTime(startTime)}] 자식 코루틴 실행 완료")
11 | }
12 | println("[${getElapsedTime(startTime)}] 부모 코루틴이 실행하는 마지막 코드")
13 | }
14 | parentJob.invokeOnCompletion { // 부모 코루틴이 종료될 시 호출되는 콜백 등록
15 | println("[${getElapsedTime(startTime)}] 부모 코루틴 실행 완료")
16 | }
17 | delay(500L) // 500밀리초간 대기
18 | println(parentJob) // parentJob Debug String 출력
19 | printJobState(parentJob) // parentJob 상태 출력
20 | }
21 |
22 | private fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
23 |
24 | private fun printJobState(job: Job) {
25 | println(
26 | "Job State\n" +
27 | "isActive >> ${job.isActive}\n" +
28 | "isCancelled >> ${job.isCancelled}\n" +
29 | "isCompleted >> ${job.isCompleted} "
30 | )
31 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code11/Code7-11.kt:
--------------------------------------------------------------------------------
1 | package section7.code11
2 |
3 | import kotlinx.coroutines.*
4 | import kotlin.coroutines.CoroutineContext
5 |
6 | class CustomCoroutineScope : CoroutineScope {
7 | override val coroutineContext: CoroutineContext = Job() +
8 | newSingleThreadContext("CustomScopeThread")
9 | }
10 |
11 | fun main() {
12 | val coroutineScope = CustomCoroutineScope() // CustomCoroutineScope 인스턴스화
13 | coroutineScope.launch {
14 | delay(100L) // 100밀리초 대기
15 | println("[${Thread.currentThread().name}] 코루틴 실행 완료")
16 | }
17 | Thread.sleep(1000L) // 코드 종료 방지
18 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code12/Code7-12.kt:
--------------------------------------------------------------------------------
1 | package section7.code12
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() {
6 | val coroutineScope = CoroutineScope(Dispatchers.IO)
7 | coroutineScope.launch {
8 | delay(100L) // 100밀리초 대기
9 | println("[${Thread.currentThread().name}] 코루틴 실행 완료")
10 | }
11 | Thread.sleep(1000L)
12 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code13/Code7-13.kt:
--------------------------------------------------------------------------------
1 | package section7.code13
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() {
6 | val newScope = CoroutineScope(CoroutineName("MyCoroutine") + Dispatchers.IO)
7 | newScope.launch(context = CoroutineName("LaunchCoroutine")) {
8 | println("newScope의 coroutineContext: ${newScope.coroutineContext}")
9 | println("launch 코루틴의 coroutineContext: ${this.coroutineContext}")
10 | println("launch 코루틴의 parentJob: ${this.coroutineContext[Job]?.parent}")
11 | }
12 | Thread.sleep(1000L)
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code14/Code7-14.kt:
--------------------------------------------------------------------------------
1 | package section7.code14
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() {
6 | val newScope = CoroutineScope(CoroutineName("MyCoroutine") + Dispatchers.IO)
7 | newScope.launch(CoroutineName("LaunchCoroutine")) {
8 | this.launch { // CoroutineScope으로부터 LaunchCoroutine의 실행 환경을 제공 받아 코루틴 실행
9 | // 작업 실행
10 | }
11 | }
12 | Thread.sleep(1000L)
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code15/Code7-15.kt:
--------------------------------------------------------------------------------
1 | package section7.code15
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() {
6 | val newScope = CoroutineScope(CoroutineName("MyCoroutine") + Dispatchers.IO)
7 | newScope.launch(CoroutineName("LaunchCoroutine")) {
8 | launch { // CoroutineScope으로부터 LaunchCoroutine의 실행 환경을 제공 받아 코루틴 실행
9 | // 작업 실행
10 | }
11 | }
12 | Thread.sleep(1000L)
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code16/Code7-16.kt:
--------------------------------------------------------------------------------
1 | package section7.code16
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | this.launch {
7 | this.async {
8 | // 작업 실행
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code17/Code7-17.kt:
--------------------------------------------------------------------------------
1 | package section7.code17
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(CoroutineName("Coroutine1")) {
7 | launch(CoroutineName("Coroutine3")) {
8 | println("[${Thread.currentThread().name}] 코루틴 실행")
9 | }
10 | launch(CoroutineName("Coroutine4")) {
11 | println("[${Thread.currentThread().name}] 코루틴 실행")
12 | }
13 | }
14 |
15 | launch(CoroutineName("Coroutine2")) {
16 | println("[${Thread.currentThread().name}] 코루틴 실행")
17 | }
18 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code18/Code7-18.kt:
--------------------------------------------------------------------------------
1 | package section7.code18
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(CoroutineName("Coroutine1")) {
7 | launch(CoroutineName("Coroutine3")) {
8 | println("[${Thread.currentThread().name}] 코루틴 실행")
9 | }
10 | CoroutineScope(Dispatchers.IO).launch(CoroutineName("Coroutine4")) {
11 | println("[${Thread.currentThread().name}] 코루틴 실행")
12 | }
13 | }
14 |
15 | launch(CoroutineName("Coroutine2")) {
16 | println("[${Thread.currentThread().name}] 코루틴 실행")
17 | }
18 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code19/Code7-19.kt:
--------------------------------------------------------------------------------
1 | package section7.code19
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(CoroutineName("Coroutine1")) {
7 | launch(CoroutineName("Coroutine3")) {
8 | delay(100L)
9 | println("[${Thread.currentThread().name}] 코루틴 실행 완료")
10 | }
11 | launch(CoroutineName("Coroutine4")) {
12 | delay(100L)
13 | println("[${Thread.currentThread().name}] 코루틴 실행 완료")
14 | }
15 | this.cancel() // Coroutine1의 CoroutineScope에 cancel 요청
16 | }
17 |
18 | launch(CoroutineName("Coroutine2")) {
19 | delay(100L)
20 | println("[${Thread.currentThread().name}] 코루틴 실행 완료")
21 | }
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code2/Code7-2.kt:
--------------------------------------------------------------------------------
1 | package section7.code2
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val coroutineContext = newSingleThreadContext("MyThread") + CoroutineName("CoroutineA")
7 | launch(coroutineContext){ // 부모 코루틴 생성
8 | println("[${Thread.currentThread().name}] 부모 코루틴 실행")
9 | launch { // 자식 코루틴 생성
10 | println("[${Thread.currentThread().name}] 자식 코루틴 실행")
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code20/Code7-20.kt:
--------------------------------------------------------------------------------
1 | package section7.code20
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val whileJob: Job = launch(Dispatchers.Default) {
7 | while(this.isActive) {
8 | println("작업 중")
9 | }
10 | }
11 | delay(100L)
12 | whileJob.cancel()
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code21/Code7-21.kt:
--------------------------------------------------------------------------------
1 | package section7.code21
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking { // 루트 코루틴(루트 Job) 생성
6 | println("[${Thread.currentThread().name}] 코루틴 실행")
7 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code22/Code7-22.kt:
--------------------------------------------------------------------------------
1 | package section7.code22
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(CoroutineName("Coroutine1")) {
7 | launch(CoroutineName("Coroutine3")) {
8 | delay(100L)
9 | println("[${Thread.currentThread().name}] 코루틴 실행")
10 | }
11 | launch(CoroutineName("Coroutine4")) {
12 | delay(100L)
13 | println("[${Thread.currentThread().name}] 코루틴 실행")
14 | }
15 | }
16 | launch(CoroutineName("Coroutine2")) {
17 | launch(CoroutineName("Coroutine5")) {
18 | delay(100L)
19 | println("[${Thread.currentThread().name}] 코루틴 실행")
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code23/Code7-23.kt:
--------------------------------------------------------------------------------
1 | package section7.code23
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking { // 루트 Job 생성
6 | val newScope = CoroutineScope(Dispatchers.IO) // 새로운 루트 Job 생성
7 | newScope.launch(CoroutineName("Coroutine1")) {
8 | launch(CoroutineName("Coroutine3")) {
9 | delay(100L)
10 | println("[${Thread.currentThread().name}] 코루틴 실행")
11 | }
12 | launch(CoroutineName("Coroutine4")) {
13 | delay(100L)
14 | println("[${Thread.currentThread().name}] 코루틴 실행")
15 | }
16 | }
17 | newScope.launch(CoroutineName("Coroutine2")) {
18 | launch(CoroutineName("Coroutine5")) {
19 | delay(100L)
20 | println("[${Thread.currentThread().name}] 코루틴 실행")
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code24/Code7-24.kt:
--------------------------------------------------------------------------------
1 | package section7.code24
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking { // 루트 Job 생성
6 | val newScope = CoroutineScope(Dispatchers.IO) // 새로운 루트 Job 생성
7 | newScope.launch(CoroutineName("Coroutine1")) {
8 | launch(CoroutineName("Coroutine3")) {
9 | delay(100L)
10 | println("[${Thread.currentThread().name}] 코루틴 실행")
11 | }
12 | launch(CoroutineName("Coroutine4")) {
13 | delay(100L)
14 | println("[${Thread.currentThread().name}] 코루틴 실행")
15 | }
16 | }
17 | newScope.launch(CoroutineName("Coroutine2")) {
18 | launch(CoroutineName("Coroutine5")) {
19 | delay(100L)
20 | println("[${Thread.currentThread().name}] 코루틴 실행")
21 | }
22 | }
23 | delay(1000L)
24 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code25/Code7-25.kt:
--------------------------------------------------------------------------------
1 | package section7.code25
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val newRootJob = Job() // 루트 Job 생성
7 | launch(CoroutineName("Coroutine1") + newRootJob) {
8 | launch(CoroutineName("Coroutine3")) {
9 | delay(100L)
10 | println("[${Thread.currentThread().name}] 코루틴 실행")
11 | }
12 | launch(CoroutineName("Coroutine4")) {
13 | delay(100L)
14 | println("[${Thread.currentThread().name}] 코루틴 실행")
15 | }
16 | }
17 | launch(CoroutineName("Coroutine2") + newRootJob) {
18 | launch(CoroutineName("Coroutine5")) {
19 | delay(100L)
20 | println("[${Thread.currentThread().name}] 코루틴 실행")
21 | }
22 | }
23 | delay(1000L)
24 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code26/Code7-26.kt:
--------------------------------------------------------------------------------
1 | package section7.code26
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val newRootJob = Job() // 루트 Job 생성
7 | launch(CoroutineName("Coroutine1") + newRootJob) {
8 | launch(CoroutineName("Coroutine3")) {
9 | delay(100L)
10 | println("[${Thread.currentThread().name}] 코루틴 실행")
11 | }
12 | launch(CoroutineName("Coroutine4")) {
13 | delay(100L)
14 | println("[${Thread.currentThread().name}] 코루틴 실행")
15 | }
16 | }
17 | launch(CoroutineName("Coroutine2") + newRootJob) {
18 | launch(CoroutineName("Coroutine5")) {
19 | delay(100L)
20 | println("[${Thread.currentThread().name}] 코루틴 실행")
21 | }
22 | }
23 | newRootJob.cancel() // newRootJob 취소
24 | delay(1000L)
25 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code27/Code7-27.kt:
--------------------------------------------------------------------------------
1 | package section7.code27
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val newRootJob = Job()
7 | launch(CoroutineName("Coroutine1") + newRootJob) {
8 | launch(CoroutineName("Coroutine3")) {
9 | delay(100L)
10 | println("[${Thread.currentThread().name}] 코루틴 실행")
11 | }
12 | launch(CoroutineName("Coroutine4")) {
13 | delay(100L)
14 | println("[${Thread.currentThread().name}] 코루틴 실행")
15 | }
16 | }
17 | launch(CoroutineName("Coroutine2") + newRootJob) {
18 | launch(CoroutineName("Coroutine5") + Job()) {
19 | delay(100L)
20 | println("[${Thread.currentThread().name}] 코루틴 실행")
21 | }
22 | }
23 | delay(50L) // 모든 코루틴이 생성될 때까지 대기
24 | newRootJob.cancel() // 새로운 루트 Job 취소
25 | delay(1000L)
26 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code28/Code7-28.kt:
--------------------------------------------------------------------------------
1 | package section7.code28
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(CoroutineName("Coroutine1")) {
7 | val newJob = Job()
8 | launch(CoroutineName("Coroutine2") + newJob) {
9 | delay(100L)
10 | println("[${Thread.currentThread().name}] 코루틴 실행")
11 | }
12 | }
13 | delay(1000L)
14 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code29/Code7-29.kt:
--------------------------------------------------------------------------------
1 | package section7.code29
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(CoroutineName("Coroutine1")) {
7 | val coroutine1Job = this.coroutineContext[Job] // Coroutine1의 Job
8 | val newJob = Job(parent = coroutine1Job)
9 | launch(CoroutineName("Coroutine2") + newJob) {
10 | delay(100L)
11 | println("[${Thread.currentThread().name}] 코루틴 실행")
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code3/Code7-3.kt:
--------------------------------------------------------------------------------
1 | package section7.code3
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val coroutineContext = newSingleThreadContext("MyThread") + CoroutineName("ParentCoroutine")
7 | launch(coroutineContext){ // 부모 코루틴 생성
8 | println("[${Thread.currentThread().name}] 부모 코루틴 실행")
9 | launch(CoroutineName("ChildCoroutine")) { // 자식 코루틴 생성
10 | println("[${Thread.currentThread().name}] 자식 코루틴 실행")
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code30/Code7-30.kt:
--------------------------------------------------------------------------------
1 | package section7.code30
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(CoroutineName("Coroutine1")) {
7 | val coroutine1Job = this.coroutineContext[Job]
8 | val newJob = Job(coroutine1Job)
9 | launch(CoroutineName("Coroutine2") + newJob) {
10 | delay(100L)
11 | println("[${Thread.currentThread().name}] 코루틴 실행")
12 | }
13 | newJob.complete() // 명시적으로 완료 호출
14 | }
15 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code31/Code7-31.kt:
--------------------------------------------------------------------------------
1 | package section7.code31
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | delay(5000L)
7 | println("[${Thread.currentThread().name}] 코루틴 종료")
8 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code32/Code7-32.kt:
--------------------------------------------------------------------------------
1 | package section7.code32
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch {
7 | delay(1000L)
8 | println("[${Thread.currentThread().name}] launch 코루틴 종료")
9 | }
10 | delay(2000L)
11 | println("[${Thread.currentThread().name}] runBlocking 코루틴 종료")
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code4/Code7-4.kt:
--------------------------------------------------------------------------------
1 | package section7.code4
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking { // 부모 코루틴 생성
6 | val runBlockingJob = coroutineContext[Job] // 부모 코루틴의 Job 추출
7 | launch { // 자식 코루틴 생성
8 | val launchJob = coroutineContext[Job] // 자식 코루틴의 Job 추출
9 | if (runBlockingJob === launchJob) {
10 | println("runBlocking으로 생성된 Job과 launch로 생성된 Job이 동일합니다")
11 | } else {
12 | println("runBlocking으로 생성된 Job과 launch로 생성된 Job이 다릅니다")
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code5/Code7-5.kt:
--------------------------------------------------------------------------------
1 | package section7.code5
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val runBlockingJob = coroutineContext[Job]
7 | println(runBlockingJob?.parent)
8 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code6/Code7-6.kt:
--------------------------------------------------------------------------------
1 | package section7.code6
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking { // 부모 코루틴
6 | val parentJob = coroutineContext[Job] // 부모 코루틴의 CoroutineContext로부터 부모 코루틴의 Job 추출
7 | launch { // 자식 코루틴
8 | val childJob = coroutineContext[Job] // 자식 코루틴의 CoroutineContext로부터 자식 코루틴의 Job 추출
9 | println("1. 자식 코루틴의 Job이 가지고 있는 parent는 부모 코루틴의 Job인가? ${childJob?.parent === parentJob}")
10 | println("2. 부모 코루틴의 Job은 자식 코루틴의 Job을 참조를 가지는가? ${parentJob?.children?.contains(childJob)}")
11 | }
12 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code7/Code7-7.kt:
--------------------------------------------------------------------------------
1 | package section7.code7
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val parentJob = launch(Dispatchers.IO) { // 부모 코루틴 생성
7 | val dbResultsDeferred: List> = listOf("db1", "db2", "db3").map {
8 | async { // 자식 코루틴 생성
9 | delay(1000L) // DB로부터 데이터를 가져오는데 걸리는 시간
10 | println("${it}로부터 데이터를 가져오는데 성공했습니다")
11 | return@async "[${it}]data"
12 | }
13 | }
14 | val dbResults: List = dbResultsDeferred.awaitAll() // 모든 코루틴이 완료될 때까지 대기
15 |
16 | println(dbResults) // 화면에 표시
17 | }
18 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code8/Code7-8.kt:
--------------------------------------------------------------------------------
1 | package section7.code8
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val parentJob = launch(Dispatchers.IO){ // 부모 코루틴 생성
7 | val dbResultsDeferred: List> = listOf("db1","db2","db3").map {
8 | async { // 자식 코루틴 생성
9 | delay(1000L) // DB로부터 데이터를 가져오는데 걸리는 시간
10 | println("${it}로부터 데이터를 가져오는데 성공했습니다")
11 | return@async "[${it}]data"
12 | }
13 | }
14 | val dbResults: List = dbResultsDeferred.awaitAll() // 모든 코루틴이 완료될 때까지 대기
15 |
16 | println(dbResults) // 화면에 표시
17 | }
18 | parentJob.cancel() // 부모 코루틴에 취소 요청
19 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section7/code9/Code7-9.kt:
--------------------------------------------------------------------------------
1 | package section7.code9
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | val parentJob = launch { // 부모 코루틴 실행
8 | launch { // 자식 코루틴 실행
9 | delay(1000L) // 1초간 대기
10 | println("[${getElapsedTime(startTime)}] 자식 코루틴 실행 완료")
11 | }
12 | println("[${getElapsedTime(startTime)}] 부모 코루틴이 실행하는 마지막 코드")
13 | }
14 | parentJob.invokeOnCompletion { // 부모 코루틴이 완료될 시 호출되는 콜백 등록
15 | println("[${getElapsedTime(startTime)}] 부모 코루틴 실행 완료")
16 | }
17 | }
18 |
19 | private fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code1/Code8-1.kt:
--------------------------------------------------------------------------------
1 | package section8.code1
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(CoroutineName("Coroutine1")) {
7 | launch(CoroutineName("Coroutine3")) {
8 | throw Exception("예외 발생")
9 | }
10 | delay(100L)
11 | println("[${Thread.currentThread().name}] 코루틴 실행")
12 | }
13 | launch(CoroutineName("Coroutine2")) {
14 | delay(100L)
15 | println("[${Thread.currentThread().name}] 코루틴 실행")
16 | }
17 | delay(1000L)
18 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code10/Code8-10.kt:
--------------------------------------------------------------------------------
1 | package section8.code10
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
7 | println("[예외 발생] ${throwable}")
8 | }
9 | CoroutineScope(Dispatchers.IO).launch(CoroutineName("Coroutine1")) {
10 | launch(CoroutineName("Coroutine2") + exceptionHandler) {
11 | throw Exception("Coroutine2에 예외가 발생했습니다")
12 | }
13 | }
14 | delay(1000L)
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code11/Code8-11.kt:
--------------------------------------------------------------------------------
1 | package section8.code11
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
7 | println("[예외 발생] ${throwable}")
8 | }
9 | val exceptionHandler2 = CoroutineExceptionHandler { coroutineContext, throwable ->
10 | println("[예외 발생2] ${throwable}")
11 | }
12 |
13 | CoroutineScope(exceptionHandler)
14 | .launch(CoroutineName("Coroutine1") + exceptionHandler2) {
15 | launch(CoroutineName("Coroutine2")) {
16 | throw Exception("Coroutine2에 예외가 발생했습니다")
17 | }
18 | }
19 | delay(1000L)
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code12/Code8-12.kt:
--------------------------------------------------------------------------------
1 | package section8.code12
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
7 | println("[예외 로깅] ${throwable}")
8 | }
9 |
10 | CoroutineScope(Dispatchers.IO)
11 | .launch(CoroutineName("Coroutine1") + exceptionHandler) {
12 | launch(CoroutineName("Coroutine2")) {
13 | throw Exception("Coroutine2에 예외가 발생했습니다")
14 | }
15 | launch(CoroutineName("Coroutine3")) {
16 | // 다른 작업
17 | }
18 | }
19 |
20 | delay(1000L)
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code13/Code8-13.kt:
--------------------------------------------------------------------------------
1 | package section8.code13
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(CoroutineName("Coroutine1")) {
7 | try {
8 | throw Exception("Coroutine1에 예외가 발생했습니다")
9 | } catch (e: Exception) {
10 | println(e.message)
11 | }
12 | }
13 | launch(CoroutineName("Coroutine2")) {
14 | delay(100L)
15 | println("Coroutine2 실행 완료")
16 | }
17 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code14/Code8-14.kt:
--------------------------------------------------------------------------------
1 | package section8.code14
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | try {
7 | launch(CoroutineName("Coroutine1")) {
8 | throw Exception("Coroutine1에 예외가 발생했습니다")
9 | }.join()
10 | } catch (e: Exception) {
11 | println(e.message)
12 | }
13 | launch(CoroutineName("Coroutine2")) {
14 | delay(100L)
15 | println("Coroutine2 실행 완료")
16 | }
17 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code15/Code8-15.kt:
--------------------------------------------------------------------------------
1 | package section8.code15
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | supervisorScope {
7 | val deferred: Deferred = async(CoroutineName("Coroutine1")) {
8 | throw Exception("Coroutine1에 예외가 발생했습니다")
9 | }
10 | try {
11 | deferred.await()
12 | } catch (e: Exception) {
13 | println("[노출된 예외] ${e.message}")
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code16/Code8-16.kt:
--------------------------------------------------------------------------------
1 | package section8.code16
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | async(CoroutineName("Coroutine1")) {
7 | throw Exception("Coroutine1에 예외가 발생했습니다")
8 | }
9 | launch(CoroutineName("Coroutine2")) {
10 | delay(100L)
11 | println("[${Thread.currentThread().name}] 코루틴 실행")
12 | }
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code17/Code8-17.kt:
--------------------------------------------------------------------------------
1 | package section8.code17
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | supervisorScope {
7 | async(CoroutineName("Coroutine1")) {
8 | throw Exception("Coroutine1에 예외가 발생했습니다")
9 | }
10 | launch(CoroutineName("Coroutine2")) {
11 | delay(100L)
12 | println("[${Thread.currentThread().name}] 코루틴 실행")
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code18/Code8-18.kt:
--------------------------------------------------------------------------------
1 | package section8.code18
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking(CoroutineName("runBlocking 코루틴")) {
6 | launch(CoroutineName("Coroutine1")) {
7 | launch(CoroutineName("Coroutine2")) {
8 | throw CancellationException()
9 | }
10 | delay(100L)
11 | println("[${Thread.currentThread().name}] 코루틴 실행")
12 | }
13 | delay(100L)
14 | println("[${Thread.currentThread().name}] 코루틴 실행")
15 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code19/Code8-19.kt:
--------------------------------------------------------------------------------
1 | package section8.code19
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val job = launch {
7 | delay(1000L) // 1초간 지속
8 | }
9 | job.invokeOnCompletion { exception ->
10 | println(exception) // 발생한 예외 출력
11 | }
12 | job.cancel() // job 취소
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code2/Code8-2.kt:
--------------------------------------------------------------------------------
1 | package section8.code2
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(CoroutineName("Parent Coroutine")) {
7 | // 새로운 Job 객체를 만들어 Coroutine1에 연결
8 | launch(CoroutineName("Coroutine1") + Job()) {
9 | launch(CoroutineName("Coroutine3")) {
10 | throw Exception("예외 발생")
11 | }
12 | delay(100L)
13 | println("[${Thread.currentThread().name}] 코루틴 실행")
14 | }
15 | launch(CoroutineName("Coroutine2")) {
16 | delay(100L)
17 | println("[${Thread.currentThread().name}] 코루틴 실행")
18 | }
19 | }
20 | delay(1000L)
21 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code3/Code8-3.kt:
--------------------------------------------------------------------------------
1 | package section8.code3
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val parentJob = launch(CoroutineName("Parent Coroutine")) {
7 | // 새로운 Job 객체를 만들어 Coroutine1에 연결
8 | launch(CoroutineName("Coroutine1") + Job()) {
9 | launch(CoroutineName("Coroutine3")) {
10 | delay(100L)
11 | println("[${Thread.currentThread().name}] 코루틴 실행")
12 | }
13 | delay(100L)
14 | println("[${Thread.currentThread().name}] 코루틴 실행")
15 | }
16 | launch(CoroutineName("Coroutine2")) {
17 | delay(100L)
18 | println("[${Thread.currentThread().name}] 코루틴 실행")
19 | }
20 | }
21 | delay(20L) // 코루틴들이 모두 생성될 때까지 대기
22 | parentJob.cancel() // Parent Coroutine에 취소 요청
23 | delay(1000L)
24 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code4/Code8-4.kt:
--------------------------------------------------------------------------------
1 | package section8.code4
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val supervisorJob = SupervisorJob()
7 | launch(CoroutineName("Coroutine1") + supervisorJob) {
8 | launch(CoroutineName("Coroutine3")) {
9 | throw Exception("예외 발생")
10 | }
11 | delay(100L)
12 | println("[${Thread.currentThread().name}] 코루틴 실행")
13 | }
14 | launch(CoroutineName("Coroutine2") + supervisorJob) {
15 | delay(100L)
16 | println("[${Thread.currentThread().name}] 코루틴 실행")
17 | }
18 | delay(1000L)
19 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code5/Code8-5.kt:
--------------------------------------------------------------------------------
1 | package section8.code5
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | // supervisorJob의 부모로 runBlocking으로 생성된 Job 객체 설정
7 | val supervisorJob = SupervisorJob(parent = this.coroutineContext[Job])
8 | launch(CoroutineName("Coroutine1") + supervisorJob) {
9 | launch(CoroutineName("Coroutine3")) {
10 | throw Exception("예외 발생")
11 | }
12 | delay(100L)
13 | println("[${Thread.currentThread().name}] 코루틴 실행")
14 | }
15 | launch(CoroutineName("Coroutine2") + supervisorJob) {
16 | delay(100L)
17 | println("[${Thread.currentThread().name}] 코루틴 실행")
18 | }
19 | supervisorJob.complete() // supervisorJob 완료 처리
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code6/Code8-6.kt:
--------------------------------------------------------------------------------
1 | package section8.code6
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val coroutineScope = CoroutineScope(SupervisorJob())
7 | coroutineScope.apply {
8 | launch(CoroutineName("Coroutine1")) {
9 | launch(CoroutineName("Coroutine3")) {
10 | throw Exception("예외 발생")
11 | }
12 | delay(100L)
13 | println("[${Thread.currentThread().name}] 코루틴 실행")
14 | }
15 | launch(CoroutineName("Coroutine2")) {
16 | delay(100L)
17 | println("[${Thread.currentThread().name}] 코루틴 실행")
18 | }
19 | }
20 | delay(1000L)
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code7/Code8-7.kt:
--------------------------------------------------------------------------------
1 | package section8.code7
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | launch(CoroutineName("Parent Coroutine") + SupervisorJob()) {
7 | launch(CoroutineName("Coroutine1")) {
8 | launch(CoroutineName("Coroutine3")) {
9 | throw Exception("예외 발생")
10 | }
11 | delay(100L)
12 | println("[${Thread.currentThread().name}] 코루틴 실행")
13 | }
14 | launch(CoroutineName("Coroutine2")) {
15 | delay(100L)
16 | println("[${Thread.currentThread().name}] 코루틴 실행")
17 | }
18 | }
19 | delay(1000L)
20 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code8/Code8-8.kt:
--------------------------------------------------------------------------------
1 | package section8.code8
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | supervisorScope {
7 | launch(CoroutineName("Coroutine1")) {
8 | launch(CoroutineName("Coroutine3")) {
9 | throw Exception("예외 발생")
10 | }
11 | delay(100L)
12 | println("[${Thread.currentThread().name}] 코루틴 실행")
13 | }
14 | launch(CoroutineName("Coroutine2")) {
15 | delay(100L)
16 | println("[${Thread.currentThread().name}] 코루틴 실행")
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section8/code9/Code8-9.kt:
--------------------------------------------------------------------------------
1 | package section8.code9
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val exceptionHandler = CoroutineExceptionHandler { coroutineContext, throwable ->
7 | println("[예외 발생] ${throwable}")
8 | }
9 | CoroutineScope(context = exceptionHandler).launch(CoroutineName("Coroutine1")) {
10 | launch(CoroutineName("Coroutine2")) {
11 | throw Exception("Coroutine2에 예외가 발생했습니다")
12 | }
13 | }
14 | delay(1000L)
15 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section9/code1/Code9-1.kt:
--------------------------------------------------------------------------------
1 | package section9.code1
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | delay(1000L)
7 | println("Hello World")
8 | delay(1000L)
9 | println("Hello World")
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/kotlin/section9/code10/Code9-10.kt:
--------------------------------------------------------------------------------
1 | package section9.code10
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | val results = searchByKeyword("Keyword") // 검색 실행 및 결과 값 반환 받기
8 | println("[결과] ${results.toList()}") // 결과값 출력
9 | println(getElapsedTime(startTime))
10 | }
11 |
12 | suspend fun searchByKeyword(keyword: String): Array = coroutineScope {
13 | val dbResultsDeferred = async {
14 | searchFromDB(keyword)
15 | }
16 | val serverResultsDeferred = async {
17 | searchFromServer(keyword)
18 | }
19 |
20 | return@coroutineScope arrayOf(*dbResultsDeferred.await(), *serverResultsDeferred.await())
21 | }
22 |
23 | suspend fun searchFromDB(keyword: String): Array {
24 | delay(1000L)
25 | return arrayOf("[DB]${keyword}1", "[DB]${keyword}2")
26 | }
27 |
28 | suspend fun searchFromServer(keyword: String): Array {
29 | delay(1000L)
30 | return arrayOf("[Server]${keyword}1", "[Server]${keyword}2")
31 | }
32 |
33 | fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
34 |
--------------------------------------------------------------------------------
/src/main/kotlin/section9/code11/Code9-11.kt:
--------------------------------------------------------------------------------
1 | package section9.code11
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | val results = searchByKeyword("Keyword") // 검색 실행 및 결과 값 반환 받기
8 | println("[결과] ${results.toList()}") // 결과값 출력
9 | println(getElapsedTime(startTime))
10 | }
11 |
12 | suspend fun searchByKeyword(keyword: String): Array = coroutineScope {
13 | val dbResultsDeferred = async {
14 | throw Exception("DB 읽기 오류 발생")
15 | searchFromDB(keyword)
16 | }
17 | val serverResultsDeferred = async {
18 | searchFromServer(keyword)
19 | }
20 |
21 | return@coroutineScope arrayOf(*dbResultsDeferred.await(), *serverResultsDeferred.await())
22 | }
23 |
24 | suspend fun searchFromDB(keyword: String): Array {
25 | delay(1000L)
26 | return arrayOf("[DB]${keyword}1", "[DB]${keyword}2")
27 | }
28 |
29 | suspend fun searchFromServer(keyword: String): Array {
30 | delay(1000L)
31 | return arrayOf("[Server]${keyword}1", "[Server]${keyword}2")
32 | }
33 |
34 | fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
35 |
--------------------------------------------------------------------------------
/src/main/kotlin/section9/code12/Code9-12.kt:
--------------------------------------------------------------------------------
1 | package section9.code12
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | val results = searchByKeyword("Keyword") // 검색 실행 및 결과 값 반환 받기
8 | println("[결과] ${results.toList()}") // 결과값 출력
9 | println(section9.code11.getElapsedTime(startTime))
10 | }
11 |
12 | suspend fun searchByKeyword(keyword: String): Array = supervisorScope {
13 | val dbResultsDeferred = async {
14 | throw Exception("DB 읽기 오류 발생")
15 | searchFromDB(keyword)
16 | }
17 | val serverResultsDeferred = async {
18 | searchFromServer(keyword)
19 | }
20 |
21 | val dbResults = try {
22 | dbResultsDeferred.await()
23 | } catch (e: Exception) {
24 | arrayOf() // 예외 발생 시 빈 결과 반환
25 | }
26 |
27 | val serverResults = try {
28 | serverResultsDeferred.await()
29 | } catch (e: Exception) {
30 | arrayOf() // 예외 발생 시 빈 결과 반환
31 | }
32 |
33 | return@supervisorScope arrayOf(*dbResults, *serverResults)
34 | }
35 |
36 | suspend fun searchFromDB(keyword: String): Array {
37 | delay(1000L)
38 | return arrayOf("[DB]${keyword}1", "[DB]${keyword}2")
39 | }
40 |
41 | suspend fun searchFromServer(keyword: String): Array {
42 | delay(1000L)
43 | return arrayOf("[Server]${keyword}1", "[Server]${keyword}2")
44 | }
45 |
46 | fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
--------------------------------------------------------------------------------
/src/main/kotlin/section9/code2/Code9-2.kt:
--------------------------------------------------------------------------------
1 | package section9.code2
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | delayAndPrintHelloWorld()
7 | delayAndPrintHelloWorld()
8 | }
9 |
10 | suspend fun delayAndPrintHelloWorld() {
11 | delay(1000L)
12 | println("Hello World")
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/src/main/kotlin/section9/code3/Code9-3.kt:
--------------------------------------------------------------------------------
1 | package section9.code3
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | delayAndPrintHelloWorld()
8 | delayAndPrintHelloWorld()
9 | println(getElapsedTime(startTime))
10 | }
11 |
12 | suspend fun delayAndPrintHelloWorld() {
13 | delay(1000L)
14 | println("Hello World")
15 | }
16 |
17 | fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
--------------------------------------------------------------------------------
/src/main/kotlin/section9/code4/Code9-4.kt:
--------------------------------------------------------------------------------
1 | package section9.code4
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | delay(1000L)
8 | println("Hello World")
9 | delay(1000L)
10 | println("Hello World")
11 | println(getElapsedTime(startTime))
12 | }
13 |
14 | fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
--------------------------------------------------------------------------------
/src/main/kotlin/section9/code5/Code9-5.kt:
--------------------------------------------------------------------------------
1 | package section9.code5
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | val job1 = launch {
8 | delayAndPrintHelloWorld()
9 | }
10 | val job2 = launch {
11 | delayAndPrintHelloWorld()
12 | }
13 | joinAll(job1, job2)
14 | println(getElapsedTime(startTime))
15 | }
16 |
17 | suspend fun delayAndPrintHelloWorld() {
18 | delay(1000L)
19 | println("Hello World")
20 | }
21 |
22 | private fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
--------------------------------------------------------------------------------
/src/main/kotlin/section9/code6/Code9-6.kt:
--------------------------------------------------------------------------------
1 | package section9.code6
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | val startTime = System.currentTimeMillis()
7 | val job1 = launch {
8 | delay(1000L)
9 | println("Hello World")
10 | }
11 | val job2 = launch {
12 | delay(1000L)
13 | println("Hello World")
14 | }
15 | joinAll(job1, job2)
16 | println(getElapsedTime(startTime))
17 | }
18 |
19 | fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
--------------------------------------------------------------------------------
/src/main/kotlin/section9/code7/Code9-7.kt:
--------------------------------------------------------------------------------
1 | package section9.code7
2 |
3 | import kotlinx.coroutines.*
4 |
5 | fun main() = runBlocking {
6 | delayAndPrint(keyword = "부모 코루틴이 실행 중입니다")
7 | launch {
8 | delayAndPrint(keyword = "자식 코루틴이 실행 중입니다")
9 | }
10 | }
11 |
12 | suspend fun delayAndPrint(keyword: String) {
13 | delay(1000L)
14 | println(keyword)
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/kotlin/section9/code8/Code9-8.kt:
--------------------------------------------------------------------------------
1 | package section9.code8
2 |
3 | import kotlinx.coroutines.*
4 |
5 | suspend fun searchByKeyword(keyword: String): Array {
6 | val dbResults = searchFromDB(keyword)
7 | val serverResults = searchFromServer(keyword)
8 | return arrayOf(*dbResults, *serverResults)
9 | }
10 |
11 | suspend fun searchFromDB(keyword: String): Array {
12 | delay(1000L)
13 | return arrayOf("[DB]${keyword}1", "[DB]${keyword}2")
14 | }
15 |
16 | suspend fun searchFromServer(keyword: String): Array {
17 | delay(1000L)
18 | return arrayOf("[Server]${keyword}1", "[Server]${keyword}2")
19 | }
--------------------------------------------------------------------------------
/src/main/kotlin/section9/code9/Code9-9.kt:
--------------------------------------------------------------------------------
1 | package section9.code9
2 |
3 | import kotlinx.coroutines.*
4 |
5 | // 주석을 지우고 오류 확인
6 | //suspend fun searchByKeyword(keyword: String): Array {
7 | // val dbResultsDeferred = async {
8 | // searchFromDB(keyword)
9 | // }
10 | // val serverResultsDeferred = async {
11 | // searchFromServer(keyword)
12 | // }
13 | // return arrayOf(*dbResultsDeferred.await(), *serverResultsDeferred.await())
14 | //}
15 |
16 | suspend fun searchFromDB(keyword: String): Array {
17 | delay(1000L)
18 | return arrayOf("[DB]${keyword}1", "[DB]${keyword}2")
19 | }
20 |
21 | suspend fun searchFromServer(keyword: String): Array {
22 | delay(1000L)
23 | return arrayOf("[Server]${keyword}1", "[Server]${keyword}2")
24 | }
--------------------------------------------------------------------------------
/src/test/kotlin/chapter12/code1/AddUseCaseTest.kt:
--------------------------------------------------------------------------------
1 | package chapter12.code1
2 |
3 | import org.junit.jupiter.api.Assertions.assertEquals
4 | import org.junit.jupiter.api.Test
5 | import section12.code1.AddUseCase
6 |
7 | class AddUseCaseTest {
8 | @Test
9 | fun `1,2,3을 더하면 6이다`() {
10 | val addUseCase: AddUseCase = AddUseCase()
11 | val result = addUseCase.add(1, 2, 3)
12 | assertEquals(6, result)
13 | }
14 |
15 | @Test
16 | fun `실패하는 테스트_1,2,3을 더하면 5이다`() {
17 | val addUseCase: AddUseCase = AddUseCase()
18 | val result = addUseCase.add(1, 2, 3)
19 | assertEquals(5, result)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/test/kotlin/chapter12/code1/AddUseCaseTestWithBeforeEach.kt:
--------------------------------------------------------------------------------
1 | package chapter12.code1
2 |
3 | import org.junit.jupiter.api.Assertions.assertEquals
4 | import org.junit.jupiter.api.BeforeEach
5 | import org.junit.jupiter.api.Test
6 | import section12.code1.AddUseCase
7 |
8 | class AddUseCaseTestWithBeforeEach {
9 | private lateinit var addUseCase: AddUseCase
10 |
11 | @BeforeEach
12 | fun setUp() {
13 | addUseCase = AddUseCase()
14 | }
15 |
16 | @Test
17 | fun `1,2,3을 더하면 6이다`() {
18 | val result = addUseCase.add(1, 2, 3)
19 | assertEquals(6, result)
20 | }
21 |
22 | @Test
23 | fun `-1더하기 1은 0이다`() {
24 | val result = addUseCase.add(-1, 1)
25 | assertEquals(0, result)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/test/kotlin/chapter12/code2/FakeUserPhoneNumberRepository.kt:
--------------------------------------------------------------------------------
1 | package chapter12.code2
2 |
3 | import section12.code2.UserPhoneNumberRepository
4 |
5 | class FakeUserPhoneNumberRepository : UserPhoneNumberRepository {
6 | private val userPhoneNumberMap = mutableMapOf()
7 |
8 | override fun saveUserPhoneNumber(id: String, phoneNumber: String) {
9 | userPhoneNumberMap[id] = phoneNumber
10 | }
11 |
12 | override fun getPhoneNumberByUserId(id: String): String {
13 | return userPhoneNumberMap[id] ?: ""
14 | }
15 | }
--------------------------------------------------------------------------------
/src/test/kotlin/chapter12/code2/StubUserNameRepository.kt:
--------------------------------------------------------------------------------
1 | package chapter12.code2
2 |
3 | import section12.code2.UserNameRepository
4 |
5 | // 유연하지 않은 StubUserNameRepository
6 | //class StubUserNameRepository : UserNameRepository {
7 | // private val userNameMap = mapOf(
8 | // "0x1111" to "홍길동",
9 | // "0x2222" to "조세영"
10 | // )
11 | //
12 | // override fun saveUserName(id: String, name: String) {
13 | // // 구현하지 않는다.
14 | // }
15 | //
16 | // override fun getNameByUserId(id: String): String {
17 | // return userNameMap[id] ?: ""
18 | // }
19 | //}
20 |
21 | // 유연한 StubUserNameRepository
22 |
23 | class StubUserNameRepository(
24 | private val userNameMap: Map
25 | ) : UserNameRepository {
26 | override fun saveUserName(id: String, name: String) {
27 | // 구현하지 않는다.
28 | }
29 |
30 | override fun getNameByUserId(id: String): String {
31 | return userNameMap[id] ?: ""
32 | }
33 | }
--------------------------------------------------------------------------------
/src/test/kotlin/chapter12/code2/UserProfileFetcherTest.kt:
--------------------------------------------------------------------------------
1 | package chapter12.code2
2 |
3 | import org.junit.jupiter.api.Assertions.assertEquals
4 | import org.junit.jupiter.api.Test
5 | import section12.code2.UserProfileFetcher
6 |
7 | class UserProfileFetcherTest {
8 | @Test
9 | fun `UserNameRepository가 적절한 유저 프로필을 반환한다`() {
10 | // Given
11 | val userProfileFetcher = UserProfileFetcher(
12 | userNameRepository = StubUserNameRepository(
13 | userNameMap = mapOf(
14 | "0x1111" to "홍길동",
15 | "0x2222" to "조세영"
16 | )
17 | ),
18 | userPhoneNumberRepository = FakeUserPhoneNumberRepository().apply {
19 | this.saveUserPhoneNumber("0x1111", "010-xxxx-xxxx")
20 | }
21 | )
22 |
23 | // When
24 | val userProfile = userProfileFetcher.getUserProfileById("0x1111")
25 |
26 | // Then
27 | assertEquals("홍길동", userProfile.name)
28 | assertEquals("010-xxxx-xxxx", userProfile.phoneNumber)
29 | }
30 | }
--------------------------------------------------------------------------------
/src/test/kotlin/chapter12/code3/RepeatAddUseCaseTest.kt:
--------------------------------------------------------------------------------
1 | package chapter12.code3
2 |
3 | import kotlinx.coroutines.runBlocking
4 | import org.junit.jupiter.api.Assertions.assertEquals
5 | import org.junit.jupiter.api.Test
6 | import section12.code3.RepeatAddUseCase
7 |
8 | /**
9 | * 오류가 생기는 테스트
10 | * 일시 중단 함수로 인해 아래와 같이 작성하면 오류가 생긴다.
11 | */
12 | //class RepeatAddUseCaseTest {
13 | // @Test
14 | // fun `100번 더하면 100이 반환된다`() {
15 | // // Given
16 | // val repeatAddUseCase = RepeatAddUseCase()
17 | //
18 | // // When
19 | // val result = repeatAddUseCase.add(100)
20 | //
21 | // // Then
22 | // assertEquals(100, result)
23 | // }
24 | //}
25 |
26 |
27 | class RepeatAddUseCaseTest {
28 | @Test
29 | fun `100번 더하면 100이 반환된다`() = runBlocking {
30 | // Given
31 | val repeatAddUseCase = RepeatAddUseCase()
32 |
33 | // When
34 | val result = repeatAddUseCase.add(100)
35 |
36 | // Then
37 | assertEquals(100, result)
38 | }
39 | }
--------------------------------------------------------------------------------
/src/test/kotlin/chapter12/code4/RepeatAddWithDelayUseCaseTest.kt:
--------------------------------------------------------------------------------
1 | package chapter12.code4
2 |
3 | import kotlinx.coroutines.runBlocking
4 | import org.junit.jupiter.api.Assertions.assertEquals
5 | import org.junit.jupiter.api.Test
6 | import section12.code4.RepeatAddWithDelayUseCase
7 |
8 | class RepeatAddWithDelayUseCaseTest {
9 | @Test
10 | fun `runBlocking_100번 더하면 100이 반환된다`() = runBlocking {
11 | // Given
12 | val repeatAddUseCase = RepeatAddWithDelayUseCase()
13 |
14 | // When
15 | val result = repeatAddUseCase.add(repeatTime = 100)
16 |
17 | // Then
18 | assertEquals(100, result)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/test/kotlin/chapter12/code5/TestCoroutineScheduler.kt:
--------------------------------------------------------------------------------
1 | package chapter12.code5
2 |
3 | import kotlinx.coroutines.CoroutineScope
4 | import kotlinx.coroutines.ExperimentalCoroutinesApi
5 | import kotlinx.coroutines.delay
6 | import kotlinx.coroutines.launch
7 | import kotlinx.coroutines.test.*
8 | import kotlinx.coroutines.test.TestCoroutineScheduler
9 | import org.junit.jupiter.api.Assertions
10 | import org.junit.jupiter.api.Assertions.assertEquals
11 | import org.junit.jupiter.api.Test
12 |
13 | @OptIn(ExperimentalCoroutinesApi::class)
14 | class TestCoroutineScheduler {
15 | @Test
16 | fun `가상 시간 조절 테스트`() {
17 | val testCoroutineScheduler = TestCoroutineScheduler()
18 |
19 | testCoroutineScheduler.advanceTimeBy(5000L) // 5초를 흐르게 만듦
20 | assertEquals(5000L, testCoroutineScheduler.currentTime) // 현재 시간이 5초임을 단언
21 | testCoroutineScheduler.advanceTimeBy(6000L) // 6초를 흐르게 만듦
22 | assertEquals(11000L, testCoroutineScheduler.currentTime) // 현재 시간이 11초임을 단언
23 | testCoroutineScheduler.advanceTimeBy(10000L) // 10초를 흐르게 만듦
24 | assertEquals(21000L, testCoroutineScheduler.currentTime) // 현재 시간이 21초임을 단언
25 | }
26 |
27 | @Test
28 | fun `가상 시간 위에서 테스트 진행`() {
29 | // Given
30 | val testCoroutineScheduler: TestCoroutineScheduler = TestCoroutineScheduler()
31 | val testDispatcher: TestDispatcher = StandardTestDispatcher(scheduler = testCoroutineScheduler)
32 | val testCoroutineScope = CoroutineScope(context = testDispatcher)
33 |
34 | var result = 0
35 |
36 | // When
37 | testCoroutineScope.launch {
38 | delay(10000L) // 10초간 대기
39 | result = 1
40 | delay(10000L) // 10초간 대기
41 | result = 2
42 | }
43 |
44 | // Then
45 | testCoroutineScheduler.advanceTimeBy(5000L) // 5초를 흐르게 만듦
46 | assertEquals(0, result)
47 | testCoroutineScheduler.advanceTimeBy(6000L) // 6초를 흐르게 만듦
48 | assertEquals(1, result)
49 | testCoroutineScheduler.advanceTimeBy(10000L) // 10초를 흐르게 만듦
50 | assertEquals(2, result)
51 | }
52 |
53 | @Test
54 | fun `advanceUntilIdle의 동작 살펴보기`() {
55 | // Given
56 | val testCoroutineScheduler: TestCoroutineScheduler = TestCoroutineScheduler()
57 | val testDispatcher: TestDispatcher = StandardTestDispatcher(scheduler = testCoroutineScheduler)
58 | val testCoroutineScope = CoroutineScope(context = testDispatcher)
59 |
60 | var result = 0
61 |
62 | // When
63 | testCoroutineScope.launch {
64 | delay(10_000L) // 10초간 대기
65 | result = 1
66 | delay(10_000L) // 10초간 대기
67 | result = 2
68 | }
69 | testCoroutineScheduler.advanceUntilIdle() // testCoroutineScope 하위의 코루틴이 모두 실행되게 만듦
70 |
71 | // Then
72 | assertEquals(2, result)
73 | }
74 |
75 | @Test
76 | fun `StandardTestDispatcher 사용하기`() {
77 | // 테스트 환경 설정
78 | val testDispatcher: TestDispatcher = StandardTestDispatcher()
79 | val testCoroutineScope = CoroutineScope(context = testDispatcher)
80 |
81 | var result = 0
82 |
83 | // When
84 | testCoroutineScope.launch {
85 | delay(10_000L) // 10초간 대기
86 | result = 1
87 | delay(10_000L) // 10초간 대기
88 | result = 2
89 | }
90 | testDispatcher.scheduler.advanceUntilIdle()
91 |
92 | // Then
93 | assertEquals(2, result)
94 | }
95 |
96 | @Test
97 | fun `TestScope 사용하기`() {
98 | // Given
99 | val testCoroutineScope: TestScope = TestScope()
100 |
101 | var result = 0
102 |
103 | // When
104 | testCoroutineScope.launch {
105 | delay(10000L) // 10초간 대기
106 | result = 1
107 | delay(10000L) // 10초간 대기
108 | result = 2
109 | }
110 | testCoroutineScope.advanceUntilIdle()
111 |
112 | // Then
113 | assertEquals(2, result)
114 | }
115 |
116 | @Test
117 | fun `runTest 사용하기`() {
118 | // Given
119 | var result = 0
120 |
121 | // When
122 | runTest {
123 | delay(10000L) // 10초간 대기
124 | result = 1
125 | delay(10000L) // 10초간 대기
126 | result = 2
127 | }
128 |
129 | // Then
130 | assertEquals(2, result)
131 | }
132 |
133 | @Test
134 | fun `runTest로 테스트 감싸기`() = runTest {
135 | // Given
136 | var result = 0
137 |
138 | // When
139 | delay(10000L) // 10초간 대기
140 | result = 1
141 | delay(10000L) // 10초간 대기
142 | result = 2
143 |
144 | // Then
145 | assertEquals(2, result)
146 | }
147 |
148 | @Test
149 | fun `runTest 내부에서 advanceUntilIdle 사용하기`() = runTest {
150 | var result = 0
151 | launch {
152 | delay(1000L)
153 | result = 1
154 | }
155 |
156 | println("가상 시간: ${this.currentTime}ms, result = ${result}")
157 | advanceUntilIdle()
158 | println("가상 시간: ${this.currentTime}ms, result = ${result}")
159 | }
160 | }
--------------------------------------------------------------------------------
/src/test/kotlin/chapter12/code6/FollowerSearcherTest.kt:
--------------------------------------------------------------------------------
1 | package chapter12.code6
2 |
3 | import kotlinx.coroutines.test.runTest
4 | import org.junit.jupiter.api.Assertions
5 | import org.junit.jupiter.api.BeforeEach
6 | import org.junit.jupiter.api.Test
7 | import section12.code6.Follower
8 | import section12.code6.FollowerSearcher
9 |
10 | class FollowerSearcherTest {
11 | private lateinit var followerSearcher: FollowerSearcher
12 |
13 | @BeforeEach
14 | fun setUp() {
15 | followerSearcher = FollowerSearcher(
16 | officialAccountRepository = stubOfficialAccountRepository,
17 | personAccountRepository = stubPersonAccountRepository
18 | )
19 | }
20 |
21 | @Test
22 | fun `공식 계정과 개인 계정이 합쳐져 반환되는지 테스트`() = runTest {
23 | // Given
24 | val searchName = "A"
25 | val expectedResults = listOf(companyA, personA)
26 |
27 | // When
28 | val results = followerSearcher.searchByName(searchName)
29 |
30 | // Then
31 | Assertions.assertEquals(expectedResults, results)
32 | }
33 |
34 | @Test
35 | fun `빈 배열이 반환되는지 테스트`() = runTest {
36 | // Given
37 | val searchName = "Empty"
38 | val expectedResults = emptyList()
39 |
40 | // When
41 | val results = followerSearcher.searchByName(searchName)
42 |
43 | // Then
44 | Assertions.assertEquals(expectedResults, results)
45 | }
46 |
47 | companion object {
48 | private val companyA = Follower.OfficialAccount(id = "0x0000", name = "CompanyA")
49 | private val companyB = Follower.OfficialAccount(id = "0x0001", name = "CompanyB")
50 | private val companyC = Follower.OfficialAccount(id = "0x0002", name = "CompanyC")
51 |
52 | private val stubOfficialAccountRepository = StubOfficialAccountRepository(
53 | users = listOf(companyA, companyB, companyC)
54 | )
55 |
56 | private val personA = Follower.PersonAccount(id = "0x1000", name = "PersonA")
57 | private val personB = Follower.PersonAccount(id = "0x1001", name = "PersonB")
58 | private val personC = Follower.PersonAccount(id = "0x1002", name = "PersonC")
59 |
60 | private val stubPersonAccountRepository = StubPersonAccountRepository(
61 | users = listOf(personA, personB, personC)
62 | )
63 | }
64 | }
--------------------------------------------------------------------------------
/src/test/kotlin/chapter12/code6/StubOfficialAccountRepository.kt:
--------------------------------------------------------------------------------
1 | package chapter12.code6
2 |
3 | import kotlinx.coroutines.delay
4 | import section12.code6.Follower
5 | import section12.code6.OfficialAccountRepository
6 |
7 | class StubOfficialAccountRepository(
8 | private val users: List
9 | ) : OfficialAccountRepository {
10 | override suspend fun searchByName(name: String): Array {
11 | delay(1000L)
12 | return users.filter { user ->
13 | user.name.contains(name)
14 | }.toTypedArray()
15 | }
16 | }
--------------------------------------------------------------------------------
/src/test/kotlin/chapter12/code6/StubPersonAccountRepository.kt:
--------------------------------------------------------------------------------
1 | package chapter12.code6
2 |
3 | import kotlinx.coroutines.delay
4 | import section12.code6.Follower
5 | import section12.code6.PersonAccountRepository
6 |
7 | class StubPersonAccountRepository(
8 | private val users: List
9 | ) : PersonAccountRepository {
10 | override suspend fun searchByName(name: String): Array {
11 | delay(1000L)
12 | return users.filter { user ->
13 | user.name.contains(name)
14 | }.toTypedArray()
15 | }
16 | }
--------------------------------------------------------------------------------
/src/test/kotlin/chapter12/code7/StringStateHolderTestFail.kt:
--------------------------------------------------------------------------------
1 | package chapter12.code7
2 |
3 | import kotlinx.coroutines.test.advanceUntilIdle
4 | import kotlinx.coroutines.test.runTest
5 | import org.junit.jupiter.api.Assertions.assertEquals
6 | import org.junit.jupiter.api.Test
7 | import section12.code7.StringStateHolder
8 |
9 |
10 | class StringStateHolderTestFail {
11 | @Test
12 | fun `updateStringWithDelay(ABC)가 호출되면 문자열이 ABC로 변경된다`() = runTest {
13 | // Given
14 | val stringStateHolder = StringStateHolder()
15 |
16 | // When
17 | stringStateHolder.updateStringWithDelay("ABC")
18 |
19 | // Then
20 | advanceUntilIdle()
21 | assertEquals("ABC", stringStateHolder.stringState)
22 | }
23 | }
--------------------------------------------------------------------------------
/src/test/kotlin/chapter12/code7/StringStateHolderTestSuccess.kt:
--------------------------------------------------------------------------------
1 | package chapter12.code7
2 |
3 | import kotlinx.coroutines.test.StandardTestDispatcher
4 | import org.junit.jupiter.api.Assertions
5 | import org.junit.jupiter.api.Test
6 | import section12.code7.StringStateHolder
7 |
8 |
9 | class StringStateHolderTestSuccess {
10 | @Test
11 | fun `updateStringWithDelay(ABC)가 호출되면 문자열이 ABC로 변경된다`() {
12 | // Given
13 | val testDispatcher = StandardTestDispatcher()
14 | val stringStateHolder = StringStateHolder(
15 | dispatcher = testDispatcher
16 | )
17 |
18 | // When
19 | stringStateHolder.updateStringWithDelay("ABC")
20 |
21 | // Then
22 | testDispatcher.scheduler.advanceUntilIdle()
23 | Assertions.assertEquals("ABC", stringStateHolder.stringState)
24 | }
25 | }
--------------------------------------------------------------------------------
/src/test/kotlin/chapter12/code8/BackgroundScopeTest.kt:
--------------------------------------------------------------------------------
1 | package chapter12.code8
2 |
3 | import kotlinx.coroutines.delay
4 | import kotlinx.coroutines.launch
5 | import kotlinx.coroutines.test.advanceTimeBy
6 | import kotlinx.coroutines.test.runTest
7 | import org.junit.jupiter.api.Assertions
8 | import org.junit.jupiter.api.Test
9 |
10 | class BackgroundScopeTest {
11 | @Test
12 | fun `코루틴이 실행 완료될 때까지 호출 스레드를 블로킹하는 runTest`() = runTest {
13 | println(Thread.currentThread())
14 | }
15 |
16 | @Test
17 | fun `끝나지 않아 실패하는 테스트`() = runTest {
18 | var result = 0
19 |
20 | launch {
21 | while (true) {
22 | delay(1000L)
23 | result += 1
24 | }
25 | }
26 |
27 | advanceTimeBy(1500L)
28 | Assertions.assertEquals(1, result)
29 | advanceTimeBy(1000L)
30 | Assertions.assertEquals(2, result)
31 | }
32 |
33 | @Test
34 | fun `backgroundScope를 사용하는 테스트`() = runTest {
35 | var result = 0
36 |
37 | backgroundScope.launch {
38 | while (true) {
39 | delay(1000L)
40 | result += 1
41 | }
42 | }
43 |
44 | advanceTimeBy(1500L)
45 | Assertions.assertEquals(1, result)
46 | advanceTimeBy(1000L)
47 | Assertions.assertEquals(2, result)
48 | }
49 | }
--------------------------------------------------------------------------------