<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>김신건의 로그 - 위키 / java</title><description>&apos;java&apos; 카테고리 위키 페이지 최신 업데이트</description><link>https://shinkeonkim.com/</link><language>ko-KR</language><item><title>[Java] Reflection: Class, Method, Field, MethodHandle</title><link>https://shinkeonkim.com/wiki/java/java-reflection/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-reflection/</guid><pubDate>Tue, 23 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Reflection&lt;/strong&gt; 은 런타임에 클래스 메타데이터 (필드, 메서드, 어노테이션, 생성자) 를 조회하고, 컴파일 타임에 알 수 없는 객체를 생성/조작할 수 있게 해 주는 Java API. &lt;code&gt;java.lang.reflect.*&lt;/code&gt; 패키지.&lt;/p&gt;
&lt;p&gt;Spring 의 DI, Jackson 의 직렬화, JPA 의 entity 매핑, JUnit 의 테스트 메서드 호출 모두 reflection 위에서 동작. 단, 성능 비용 + 캡슐화 위반 + JVM 최적화 방해 같은 단점이 있어 일반 코드에서는 피하고 framework 가 대신 써 준다.&lt;/p&gt;
&lt;h2 id=&quot;class-객체-얻기&quot;&gt;Class 객체 얻기&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Class&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; c1 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; String.class;                           &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 컴파일 타임 알 때&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Class&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; c2 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;hello&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getClass&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 인스턴스에서&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Class&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; c3 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Class.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;forName&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;com.example.User&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);           &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 런타임 이름으로&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Class&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; c4 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ClassLoader.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getSystemClassLoader&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;loadClass&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;com.example.User&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Class.forName&lt;/code&gt; 은 클래스를 로드하고 static initializer 실행. JDBC driver 등록 같은 부수효과가 있는 코드에 사용 (&lt;code&gt;Class.forName(&quot;org.postgresql.Driver&quot;)&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id=&quot;메타데이터-조회&quot;&gt;메타데이터 조회&lt;/h2&gt;
&lt;p&gt;&amp;#x3C;CodeWithOutput
language=“java”
outputLanguage=“text”
outputLabel=“stdout”
code={`import java.lang.reflect.*;&lt;/p&gt;
&lt;p&gt;public class MetaDemo {
static class User {
private String name;
public int age;
public User() {}
public String greet(String prefix) { return prefix + ” ” + name; }
private void secret() {}
}&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;public static void main(String[] args) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    Class&amp;#x3C;?&gt; c = User.class;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    System.out.println(&quot;declared fields:&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    for (Field f : c.getDeclaredFields()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        System.out.printf(&quot;  %s %s%n&quot;, Modifier.toString(f.getModifiers()), f.getName());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    System.out.println(&quot;declared methods:&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    for (Method m : c.getDeclaredMethods()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        System.out.printf(&quot;  %s %s(%d)%n&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            Modifier.toString(m.getModifiers()), m.getName(), m.getParameterCount());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;code&gt;}   output={&lt;/code&gt;declared fields:
private name
public age
declared methods:
public greet(1)
private secret(0)`}
/&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;getDeclaredX()&lt;/code&gt; 는 private 포함 직접 선언만. &lt;code&gt;getX()&lt;/code&gt; 는 public + 상속받은 것. 이름이 헷갈리니 주의.&lt;/p&gt;
&lt;h2 id=&quot;동적-호출&quot;&gt;동적 호출&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Class&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; c &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Class.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;forName&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;com.example.User&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Object instance &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; c.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getDeclaredConstructor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;newInstance&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();      &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// no-args ctor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Method greet &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; c.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getMethod&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;greet&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, String.class);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (String) greet.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(instance, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Hello,&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);        &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// greet(&quot;Hello,&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Field name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; c.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getDeclaredField&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;name.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setAccessible&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                                         &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// private 우회&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;name.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(instance, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Alice&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;setAccessible(true)&lt;/code&gt; 는 캡슐화 우회. JDK 9 모듈 시스템 도입 후 &lt;code&gt;--add-opens&lt;/code&gt; JVM 옵션이 없으면 외부 모듈에는 적용 안 됨.&lt;/p&gt;
&lt;h2 id=&quot;어노테이션-처리&quot;&gt;어노테이션 처리&lt;/h2&gt;
&lt;!-- mdx-component: CodeWithOutput --&gt;
&lt;p&gt;&lt;code&gt;@Retention(RUNTIME)&lt;/code&gt; 가 필수. SOURCE / CLASS 로 선언된 어노테이션은 reflection 으로 조회 불가.&lt;/p&gt;
&lt;h2 id=&quot;동적-프록시&quot;&gt;동적 프록시&lt;/h2&gt;
&lt;p&gt;interface 기반 프록시 생성 (AOP 의 기본):&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Greeter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    String &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;greet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(String &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Greeter proxy &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (Greeter) Proxy.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;newProxyInstance&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Greeter.class.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getClassLoader&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Class&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;[] { Greeter.class },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    (p, method, args) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;→ &quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; method.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;Hello, &quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; args[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(proxy.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;greet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;World&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// → greet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Hello, World&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;interface 가 아닌 클래스를 프록시하려면 CGLIB / ByteBuddy 같은 바이트코드 라이브러리 필요. Spring 의 &lt;code&gt;@Configuration&lt;/code&gt; proxy 가 그 예.&lt;/p&gt;
&lt;h2 id=&quot;methodhandle-jdk-7-현대적-대안&quot;&gt;MethodHandle (JDK 7+, 현대적 대안)&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;java.lang.invoke.MethodHandle&lt;/code&gt; 은 reflection 보다 빠르고 JIT 친화적:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;MethodHandles.Lookup lookup &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; MethodHandles.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;lookup&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;MethodHandle greet &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; lookup.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;findVirtual&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    User.class,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;    &quot;greet&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    MethodType.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;methodType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(String.class, String.class)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (String) greet.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;invoke&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(user, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Hi,&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;특징:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JIT 최적화 가능&lt;/strong&gt;: 반복 호출이 reflection 보다 훨씬 빠름 (거의 native call 수준)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MethodType 으로 정확한 시그니처 명시&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VarHandle&lt;/strong&gt;: 필드 접근의 MethodHandle 대응 (atomic, volatile semantics)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lookup 의 권한&lt;/strong&gt;: 호출한 클래스의 접근 권한이 그대로 적용 (캡슐화 보존)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;라이브러리 (Jackson 신버전, ByteBuddy) 가 reflection 대신 MethodHandle 로 전환 중.&lt;/p&gt;
&lt;h2 id=&quot;성능-비용&quot;&gt;성능 비용&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;직접 호출:        1x  (baseline)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;MethodHandle:    2-3x&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Reflection:      30-100x  (cache 안 했을 때)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Reflection (cached): 5-10x&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;framework 들이 Method 객체를 캐싱해 두는 이유. 매번 &lt;code&gt;getMethod()&lt;/code&gt; 호출은 절대 금물.&lt;/p&gt;
&lt;p&gt;JDK 17 이후 JIT 가 많이 개선돼 cached reflection 의 차이는 줄었지만 여전히 hot path 에서는 피하는 게 좋다.&lt;/p&gt;
&lt;h2 id=&quot;함정과-베스트-프랙티스&quot;&gt;함정과 베스트 프랙티스&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JDK 9+ 모듈 시스템&lt;/strong&gt;: &lt;code&gt;setAccessible(true)&lt;/code&gt; 가 외부 모듈에 막힘. &lt;code&gt;--add-opens java.base/java.lang=ALL-UNNAMED&lt;/code&gt; 같은 JVM 옵션 필요&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;getName()&lt;/code&gt; vs &lt;code&gt;getCanonicalName()&lt;/code&gt; vs &lt;code&gt;getSimpleName()&lt;/code&gt;&lt;/strong&gt;: inner class / array 에서 결과 다름&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;isAssignableFrom&lt;/code&gt; 방향 주의&lt;/strong&gt;: &lt;code&gt;Animal.class.isAssignableFrom(Dog.class)&lt;/code&gt; 는 true (반대로 안 됨)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generic type erasure&lt;/strong&gt;: 런타임에 &lt;code&gt;List&amp;#x3C;String&gt;&lt;/code&gt; 의 &lt;code&gt;String&lt;/code&gt; 정보 없음. &lt;code&gt;ParameterizedType&lt;/code&gt; 으로 super class / field declaration 에서만 추출 가능 (Spring 의 &lt;code&gt;ResolvableType&lt;/code&gt; 활용)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Class.forName&lt;/code&gt;&lt;/strong&gt; 의 static 초기화 부수효과 주의&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GraalVM Native Image&lt;/strong&gt;: reflection 사용 클래스는 미리 &lt;code&gt;reflect-config.json&lt;/code&gt; 에 등록 필요&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JIT 친화적이려면 MethodHandle&lt;/strong&gt; 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[java-javabean]]&lt;/li&gt;
&lt;li&gt;[[spring-reflection]]&lt;/li&gt;
&lt;li&gt;[[spring-aop]]&lt;/li&gt;
&lt;li&gt;[[spring-bean-post-processor]]&lt;/li&gt;
&lt;li&gt;[[spring-ioc-di]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>reflection</category><category>metaprogramming</category><category>jvm</category><author>koa (김신건)</author></item><item><title>[Java] JavaBean 프로퍼티 규약</title><link>https://shinkeonkim.com/wiki/java/java-javabean/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-javabean/</guid><pubDate>Sun, 21 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;JavaBean&lt;/strong&gt; 은 다음 세 가지 규약을 만족하는 클래스:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;public no-args constructor&lt;/strong&gt; (인자 없는 public 생성자)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프로퍼티 접근자&lt;/strong&gt;: &lt;code&gt;getX()&lt;/code&gt;/&lt;code&gt;setX()&lt;/code&gt; 명명 규칙&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Serializable&lt;/strong&gt; 구현 (선택, 일부 컨텍스트에서 필수)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;원래는 1996 년 데스크톱 컴포넌트 모델용이었지만, 지금은 &lt;strong&gt;reflection 기반 framework 가 객체 상태에 접근하는 표준 인터페이스&lt;/strong&gt; 로 살아남았다. Jackson, JPA/Hibernate, Spring Data Binding, Bean Validation 등이 이 규약에 의존.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;POJO (Plain Old Java Object)&lt;/strong&gt; 는 더 느슨한 개념. 특정 framework 인터페이스를 상속하지 않은 평범한 객체. JavaBean 은 POJO 의 한 종류.&lt;/p&gt;
&lt;h2 id=&quot;명명-규칙&quot;&gt;명명 규칙&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; User&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Serializable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; String name;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; age;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; active;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; User&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {}                              &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// no-args ctor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; String &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name; }      &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// getter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; setName&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(String &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name; }  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// setter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getAge&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; age; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; setAge&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; age&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.age &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; age; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; isActive&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; active; }  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// boolean 은 is- prefix&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; setActive&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; active&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.active &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; active; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;getX()&lt;/code&gt; / &lt;code&gt;setX(T)&lt;/code&gt;: 일반 프로퍼티&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isX()&lt;/code&gt; / &lt;code&gt;setX(boolean)&lt;/code&gt;: boolean 프로퍼티 (&lt;code&gt;getX()&lt;/code&gt; 도 허용되나 &lt;code&gt;isX()&lt;/code&gt; 가 관례)&lt;/li&gt;
&lt;li&gt;property 이름은 메서드명에서 prefix 제거 후 &lt;strong&gt;첫 글자만 소문자&lt;/strong&gt; : &lt;code&gt;getURL()&lt;/code&gt; → &lt;code&gt;URL&lt;/code&gt;, &lt;code&gt;getFirstName()&lt;/code&gt; → &lt;code&gt;firstName&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;getXxx()&lt;/code&gt; 만 있고 &lt;code&gt;setXxx()&lt;/code&gt; 없으면 &lt;strong&gt;read-only property&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;introspector&quot;&gt;Introspector&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;java.beans.Introspector&lt;/code&gt; 가 reflection 으로 메서드를 스캔해 &lt;code&gt;BeanInfo&lt;/code&gt; 를 만든다:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;BeanInfo info &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Introspector.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getBeanInfo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(User.class);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (PropertyDescriptor pd &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; info.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getPropertyDescriptors&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(pd.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot; : &quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pd.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getPropertyType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// active : boolean&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// age : int&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// name : String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// class : Class  ← Object.getClass() 도 잡힘&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Spring 의 &lt;code&gt;BeanWrapper&lt;/code&gt;, Jackson 의 &lt;code&gt;ObjectMapper&lt;/code&gt;, JPA 의 &lt;code&gt;EntityManager&lt;/code&gt; 모두 내부적으로 이 메커니즘을 변형해 사용.&lt;/p&gt;
&lt;!-- mdx-component: CodeWithOutput --&gt;
&lt;p&gt;&lt;code&gt;Introspector&lt;/code&gt; 가 &lt;code&gt;getXxx&lt;/code&gt;/&lt;code&gt;setXxx&lt;/code&gt;/&lt;code&gt;isXxx&lt;/code&gt; 메서드를 스캔해 property 로 인식.&lt;/p&gt;
&lt;h2 id=&quot;no-args-constructor-의-이유&quot;&gt;no-args constructor 의 이유&lt;/h2&gt;
&lt;p&gt;framework 는 객체를 &lt;strong&gt;두 단계&lt;/strong&gt; 로 생성:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Class.newInstance()&lt;/code&gt; 로 빈 객체 생성 (no-args ctor 필요)&lt;/li&gt;
&lt;li&gt;setter 로 필드 채우기&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;DB row → entity, JSON → DTO, form → command object 같은 변환 패턴. JPA 는 &lt;code&gt;@Entity&lt;/code&gt; 에 no-args ctor 를 명시적으로 요구한다.&lt;/p&gt;
&lt;p&gt;이게 &lt;strong&gt;불변 객체와 충돌&lt;/strong&gt;. 필드를 final 로 만들고 ctor 에서만 set 하려면 no-args ctor 가 불가능. 해결책 두 가지:&lt;/p&gt;
&lt;h3 id=&quot;constructorproperties&quot;&gt;@ConstructorProperties&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; User&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; String name;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; age;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;ConstructorProperties&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;age&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; User&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(String &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; age&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.age &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; age;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; String &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getName&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getAge&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; age; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Jackson 이 &lt;code&gt;@ConstructorProperties&lt;/code&gt; 를 보고 ctor 인자명 → JSON 키 매핑. JPA 는 인식 안 함 (proxy 생성을 위해 no-args 가 여전히 필요).&lt;/p&gt;
&lt;h3 id=&quot;record-jdk-14&quot;&gt;record (JDK 14+)&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; record&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; User&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(String name, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; age) {}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;자동 생성:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;private final 필드&lt;/li&gt;
&lt;li&gt;모든 필드를 받는 canonical constructor&lt;/li&gt;
&lt;li&gt;&lt;code&gt;name()&lt;/code&gt;, &lt;code&gt;age()&lt;/code&gt; accessor (&lt;code&gt;getName()&lt;/code&gt; 아님 주의)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;equals/hashCode/toString&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;대부분 modern framework 가 record 를 직접 지원 (Jackson 2.12+, Spring Boot 2.6+). JPA 는 아직 entity 로는 부적합 (mutable 필요).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;record 와 JavaBean 의 차이&lt;/strong&gt;: accessor 이름이 &lt;code&gt;name()&lt;/code&gt; 이지 &lt;code&gt;getName()&lt;/code&gt; 이 아님. JavaBean 규약을 따르지 않으므로 일부 레거시 framework 는 record 인식 못 함.&lt;/p&gt;
&lt;h2 id=&quot;lombok-과의-관계&quot;&gt;Lombok 과의 관계&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Data&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  // = @Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;NoArgsConstructor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; User&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; String name;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; age;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lombok 은 컴파일 타임에 JavaBean 보일러플레이트를 자동 생성. JavaBean 규약을 매뉴얼하게 지키는 것과 동등.&lt;/p&gt;
&lt;p&gt;다만 &lt;code&gt;@Data&lt;/code&gt; 는 mutable + &lt;code&gt;equals/hashCode&lt;/code&gt; 자동 구현 둘 다 들어가서 JPA entity 에 쓰면 양방향 연관관계에서 무한 루프 / 영속성 컨텍스트 문제 발생. JPA entity 에는 &lt;code&gt;@Getter&lt;/code&gt; + &lt;code&gt;@Setter&lt;/code&gt; 정도만 권장.&lt;/p&gt;
&lt;h2 id=&quot;framework-별-의존&quot;&gt;framework 별 의존&lt;/h2&gt;








































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Framework&lt;/th&gt;&lt;th&gt;요구사항&lt;/th&gt;&lt;th&gt;비고&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;JPA / Hibernate&lt;/td&gt;&lt;td&gt;no-args ctor (public 또는 protected), getter/setter&lt;/td&gt;&lt;td&gt;proxy 생성을 위해&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Jackson&lt;/td&gt;&lt;td&gt;no-args ctor 또는 &lt;code&gt;@JsonCreator&lt;/code&gt; / &lt;code&gt;@ConstructorProperties&lt;/code&gt;&lt;/td&gt;&lt;td&gt;record 도 지원&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Spring &lt;code&gt;@ConfigurationProperties&lt;/code&gt;&lt;/td&gt;&lt;td&gt;setter (또는 record)&lt;/td&gt;&lt;td&gt;환경 변수 → 객체 binding&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Bean Validation&lt;/td&gt;&lt;td&gt;getter&lt;/td&gt;&lt;td&gt;필드/메서드 어디든 어노테이션 가능&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Spring MVC (&lt;code&gt;@ModelAttribute&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;no-args ctor + setter&lt;/td&gt;&lt;td&gt;form binding&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Spring &lt;code&gt;JdbcTemplate&lt;/code&gt; + &lt;code&gt;BeanPropertyRowMapper&lt;/code&gt;&lt;/td&gt;&lt;td&gt;no-args ctor + setter (또는 record)&lt;/td&gt;&lt;td&gt;RowMapper 가 reflection 사용&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;베스트-프랙티스&quot;&gt;베스트 프랙티스&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;API 응답 / 요청 DTO&lt;/strong&gt;: record 우선&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JPA entity&lt;/strong&gt;: 클래스 + &lt;code&gt;@Getter&lt;/code&gt; + &lt;code&gt;protected&lt;/code&gt; no-args ctor (Lombok &lt;code&gt;@NoArgsConstructor(access = PROTECTED)&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;@ConfigurationProperties&lt;/strong&gt;: JDK 16+ 에선 record 권장 (&lt;code&gt;spring.application.name&lt;/code&gt; 같은 단순 binding)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;불변 DTO 가 필요한데 record 가 안 맞을 때&lt;/strong&gt;: &lt;code&gt;@ConstructorProperties&lt;/code&gt; 또는 builder pattern&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[spring-data-jpa]]&lt;/li&gt;
&lt;li&gt;[[spring-jdbc-template]]&lt;/li&gt;
&lt;li&gt;[[spring-validation]]&lt;/li&gt;
&lt;li&gt;[[spring-ioc-di]]&lt;/li&gt;
&lt;li&gt;[[spring-mvc]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>javabean</category><category>convention</category><category>reflection</category><author>koa (김신건)</author></item><item><title>[Java] Servlet API: HttpServletRequest, HttpServletResponse</title><link>https://shinkeonkim.com/wiki/java/java-servlet-api/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-servlet-api/</guid><pubDate>Sun, 21 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Servlet&lt;/strong&gt; 은 Java 진영의 표준 HTTP 처리 API. 컨테이너 (Tomcat / Jetty / Undertow) 가 HTTP 요청을 객체 (&lt;code&gt;HttpServletRequest&lt;/code&gt;) 로 만들어 servlet 의 &lt;code&gt;service()&lt;/code&gt; 에 넘기고, 응답 (&lt;code&gt;HttpServletResponse&lt;/code&gt;) 을 받아 클라이언트에 송신한다.&lt;/p&gt;
&lt;p&gt;Spring MVC, JSF, Struts 같은 web framework 가 모두 이 위에서 동작. &lt;strong&gt;Spring Boot 의 &lt;code&gt;DispatcherServlet&lt;/code&gt; 도 본질적으로 하나의 Servlet&lt;/strong&gt; 이다.&lt;/p&gt;
&lt;h2 id=&quot;javax--jakarta-네임스페이스&quot;&gt;javax → jakarta 네임스페이스&lt;/h2&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;시기&lt;/th&gt;&lt;th&gt;네임스페이스&lt;/th&gt;&lt;th&gt;컨테이너&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Java EE 8 이하&lt;/td&gt;&lt;td&gt;&lt;code&gt;javax.servlet.*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Tomcat 9 이하, Jetty 9 이하&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Jakarta EE 9+&lt;/td&gt;&lt;td&gt;&lt;code&gt;jakarta.servlet.*&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Tomcat 10+, Jetty 11+&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;2019 년 Oracle 이 Java EE 를 Eclipse Foundation 에 이관하면서 &lt;code&gt;javax&lt;/code&gt; 상표를 못 쓰게 됨. 모든 import 가 강제 변경됐다. Spring Boot 3.x / Spring Framework 6 부터 &lt;code&gt;jakarta.*&lt;/code&gt; 만 지원.&lt;/p&gt;
&lt;p&gt;오래된 라이브러리가 &lt;code&gt;javax.servlet&lt;/code&gt; 을 import 하면 Spring Boot 3 에서 동작 안 함. 마이그레이션 도구 &lt;code&gt;org.eclipse.transformer&lt;/code&gt; 가 바이트코드 레벨에서 패키지 치환을 해 준다.&lt;/p&gt;
&lt;h2 id=&quot;가장-간단한-servlet&quot;&gt;가장 간단한 Servlet&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;WebServlet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/hello&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; HelloServlet&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; HttpServlet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    protected&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; doGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(HttpServletRequest &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, HttpServletResponse &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;resp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            throws&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; IOException {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        resp.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setContentType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;text/plain;charset=UTF-8&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        resp.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getWriter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;write&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Hello, &quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getParameter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;@WebServlet(&quot;/hello&quot;)&lt;/code&gt; 가 URL 매핑. &lt;code&gt;web.xml&lt;/code&gt; 으로도 가능하지만 annotation 방식이 일반적.&lt;/p&gt;
&lt;p&gt;요청과 응답 예:&lt;/p&gt;
&lt;!-- mdx-component: CodeWithOutput --&gt;
&lt;h2 id=&quot;httpservletrequest-핵심-api&quot;&gt;HttpServletRequest 핵심 API&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// URL 구성요소&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String method &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getMethod&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                 &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// &quot;GET&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String uri &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getRequestURI&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// &quot;/api/users/42&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String url &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getRequestURL&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;toString&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();     &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// &quot;http://host/api/users/42&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String query &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getQueryString&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();             &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// &quot;page=1&amp;#x26;size=10&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String contextPath &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getContextPath&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();       &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// &quot;/myapp&quot; or &quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String servletPath &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getServletPath&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();       &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// &quot;/api/users/42&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 파라미터 (query string + form body)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getParameter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] tags &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getParameterValues&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;tag&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Map&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[]&gt; all &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getParameterMap&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 헤더&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String ua &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getHeader&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;User-Agent&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Enumeration&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; names &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getHeaderNames&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; contentLength &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getContentLengthLong&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String contentType &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getContentType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 본문 (한 번만 읽을 수 있음!)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;InputStream body &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getInputStream&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 바이너리&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;BufferedReader reader &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getReader&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 텍스트&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// getReader() 또는 getInputStream() 중 하나만 호출 가능&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 쿠키, 세션&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Cookie&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] cookies &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getCookies&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;HttpSession session &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();           &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 없으면 생성&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;HttpSession existing &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getSession&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);     &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 없으면 null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 클라이언트 정보&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String ip &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getRemoteAddr&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String userAgent &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getRemoteUser&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// attribute (request scope 임시 데이터)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setAttribute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, currentUser);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;User u &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (User) req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getAttribute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;본문 한 번만 읽기&lt;/strong&gt; 가 함정. logging filter 가 본문을 미리 읽으면 controller 가 못 읽는다. Spring 의 &lt;code&gt;ContentCachingRequestWrapper&lt;/code&gt; 가 이 문제를 해결.&lt;/p&gt;
&lt;h2 id=&quot;httpservletresponse-핵심-api&quot;&gt;HttpServletResponse 핵심 API&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 상태 코드&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;resp.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setStatus&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;resp.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sendError&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;404&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Not Found&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 헤더&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;resp.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setHeader&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;X-Custom&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;resp.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;addHeader&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Set-Cookie&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;session=abc&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;resp.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setContentType&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;application/json;charset=UTF-8&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;resp.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setCharacterEncoding&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;UTF-8&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 본문 쓰기&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;PrintWriter writer &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; resp.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getWriter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;writer.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;write&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;{&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;ok&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;\&quot;&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;:true}&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 또는 바이너리&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;OutputStream out &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; resp.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getOutputStream&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;write&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(bytes);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 리다이렉트 (302)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;resp.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sendRedirect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/login&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 쿠키&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Cookie c &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Cookie&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;session&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;abc&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;c.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setHttpOnly&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;c.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setSecure&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;c.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setPath&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;c.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setMaxAge&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3600&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;resp.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;addCookie&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(c);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// flush / commit&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;resp.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;flushBuffer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 헤더 + 버퍼 즉시 전송&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 이후엔 헤더 변경 불가&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;getWriter()&lt;/code&gt; 와 &lt;code&gt;getOutputStream()&lt;/code&gt; 도 둘 중 하나만. 함께 쓰면 &lt;code&gt;IllegalStateException&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;servletcontext&quot;&gt;ServletContext&lt;/h2&gt;
&lt;p&gt;애플리케이션 전체에 1 개. &lt;strong&gt;모든 servlet 이 공유&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ServletContext ctx &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getServletContext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setAttribute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;startupTime&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Instant.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 초기화 파라미터 (web.xml 의 &amp;#x3C;context-param&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String env &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ctx.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getInitParameter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;env&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 실제 파일 시스템 경로&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String realPath &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ctx.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getRealPath&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/WEB-INF/data.json&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 동적 servlet 등록 (Servlet 3.0+)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;addServlet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;myServlet&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, MyServlet.class).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;addMapping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/api/*&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Spring 의 &lt;code&gt;application&lt;/code&gt; scope Bean 이 이 ServletContext attribute 에 저장된다 (&lt;code&gt;@Scope(&quot;application&quot;)&lt;/code&gt;).&lt;/p&gt;
&lt;h2 id=&quot;servletconfig&quot;&gt;ServletConfig&lt;/h2&gt;
&lt;p&gt;개별 servlet 의 초기화 정보:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ServletConfig cfg &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getServletConfig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    String mode &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cfg.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getInitParameter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;mode&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// web.xml 의 &amp;#x3C;init-param&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;@WebServlet(initParams = @WebInitParam(name = &quot;mode&quot;, value = &quot;prod&quot;))&lt;/code&gt; 로도 설정 가능.&lt;/p&gt;
&lt;h2 id=&quot;servlet-30-async-처리&quot;&gt;Servlet 3.0+ Async 처리&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;WebServlet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;urlPatterns&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;/slow&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;asyncSupported&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SlowServlet&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; HttpServlet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    protected&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; doGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(HttpServletRequest &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, HttpServletResponse &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;resp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        AsyncContext async &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;startAsync&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        async.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setTimeout&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10_000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // 워커 풀에 작업 위임, servlet thread 즉시 반환&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        executor.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;submit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                String result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; computeSlowly&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                async.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getResponse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getWriter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;write&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(result);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                async.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;complete&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;asyncSupported = true&lt;/code&gt; 설정 + &lt;code&gt;startAsync()&lt;/code&gt; 호출. 응답 완료까지 servlet thread 를 잡고 있지 않아 컨테이너 throughput 향상. Spring MVC 의 &lt;code&gt;Callable&lt;/code&gt; / &lt;code&gt;DeferredResult&lt;/code&gt; 가 내부적으로 이걸 사용.&lt;/p&gt;
&lt;h2 id=&quot;함정과-베스트-프랙티스&quot;&gt;함정과 베스트 프랙티스&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;본문, writer, stream 모두 1회용&lt;/strong&gt;: filter 가 미리 읽으면 컨트롤러에서 못 읽음. wrapper 패턴 사용.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;servlet 은 멀티스레드&lt;/strong&gt;: 컨테이너는 같은 인스턴스에 동시 요청을 보낸다. 인스턴스 필드 (mutable state) 두지 말 것. [[java-servlet-lifecycle]] 참고.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;HttpSession.setAttribute&lt;/code&gt;&lt;/strong&gt; 는 분산 환경에서 문제. session 객체에 직접 저장하지 말고 Redis 등 외부 store 사용 (Spring Session).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;getParameter()&lt;/code&gt;&lt;/strong&gt; 는 query string + form body 둘 다 본다. POST 본문이 &lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt; 가 아니면 body 파라미터 못 읽음 (JSON body 는 직접 stream 파싱).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;응답 commit 후 헤더 변경 불가&lt;/strong&gt;: &lt;code&gt;flushBuffer()&lt;/code&gt; 또는 본문이 buffer 크기를 넘기면 자동 commit.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[java-servlet-lifecycle]]&lt;/li&gt;
&lt;li&gt;[[java-servlet-filter]]&lt;/li&gt;
&lt;li&gt;[[java-threadlocal]]&lt;/li&gt;
&lt;li&gt;[[spring-mvc]]&lt;/li&gt;
&lt;li&gt;[[spring-dispatcher-servlet]]&lt;/li&gt;
&lt;li&gt;[[spring-webflux]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>servlet</category><category>http</category><category>web</category><category>jakarta-ee</category><author>koa (김신건)</author></item><item><title>[Java] Servlet Filter</title><link>https://shinkeonkim.com/wiki/java/java-servlet-filter/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-servlet-filter/</guid><pubDate>Sun, 21 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Filter&lt;/strong&gt; 는 servlet 호출 &lt;strong&gt;전/후&lt;/strong&gt; 에 끼어들어 요청과 응답을 가로채는 컴포넌트. 인증, 로깅, 압축, CORS, 인코딩 변환 같은 &lt;strong&gt;횡단 관심사 (cross-cutting concern)&lt;/strong&gt; 를 servlet 코드 밖에서 처리할 때 쓴다.&lt;/p&gt;
&lt;p&gt;여러 filter 가 &lt;strong&gt;체인 (chain)&lt;/strong&gt; 으로 연결돼 순차 실행된다. 마지막 filter 가 &lt;code&gt;chain.doFilter(req, resp)&lt;/code&gt; 를 호출하면 비로소 매핑된 servlet 의 &lt;code&gt;service()&lt;/code&gt; 가 실행된다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HandlerInterceptor&lt;/code&gt; 와 다른 점: &lt;strong&gt;컨테이너 레벨&lt;/strong&gt; (servlet 보다 바깥) 에서 동작. Spring 의 &lt;code&gt;DispatcherServlet&lt;/code&gt; 진입 전후 모두를 감쌀 수 있다.&lt;/p&gt;
&lt;h2 id=&quot;filter-인터페이스&quot;&gt;Filter 인터페이스&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;WebFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/api/*&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RequestLoggingFilter&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Filter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(FilterConfig &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // 컨테이너 시작 시 1회&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; doFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ServletRequest &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, ServletResponse &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;resp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, FilterChain &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;chain&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            throws&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; IOException, ServletException {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; start &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; System.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;nanoTime&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        HttpServletRequest http &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (HttpServletRequest) req;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            chain.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;doFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(req, resp);   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ← 다음 filter / servlet 으로 진행&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ms &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (System.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;nanoTime&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; start) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1_000_000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            log.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;info&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;{} {} {}ms&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, http.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getMethod&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), http.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getRequestURI&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), ms);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; destroy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/* 정리 */&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;JDK 8+ 에서 &lt;code&gt;init&lt;/code&gt; / &lt;code&gt;destroy&lt;/code&gt; 는 default 구현이 있어 생략 가능. 핵심은 &lt;code&gt;doFilter&lt;/code&gt; 하나.&lt;/p&gt;
&lt;p&gt;체인 진입/종료가 어떤 순서로 일어나는지:&lt;/p&gt;
&lt;!-- mdx-component: CodeWithOutput --&gt;
&lt;p&gt;&lt;code&gt;chain.doFilter&lt;/code&gt; 호출 전후가 명확하게 양파처럼 감싸진다.&lt;/p&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;양파 (onion) 구조. Filter A 의 chain.doFilter 호출이 Filter B 진입, Servlet 처리 후 역순으로 복귀.&lt;/p&gt;
&lt;h2 id=&quot;chaindofilter-의-의미&quot;&gt;chain.doFilter 의 의미&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Request 흐름:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ↓&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[Filter1.doFilter pre]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ↓ chain.doFilter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  [Filter2.doFilter pre]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ↓ chain.doFilter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    [Servlet.service]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    ↑&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  [Filter2.doFilter post]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ↑&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[Filter1.doFilter post]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ↓&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Response&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;chain.doFilter&lt;/code&gt; 호출 전 = 요청 전처리, 호출 후 = 응답 후처리. 호출 안 하면 &lt;strong&gt;체인 중단&lt;/strong&gt; = servlet 까지 도달하지 않음. 인증 실패 처리에 사용:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;isAuthenticated&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(http)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ((HttpServletResponse) resp).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sendError&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;401&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// chain.doFilter 호출 안 함&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;chain.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;doFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(req, resp);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;등록-방법&quot;&gt;등록 방법&lt;/h2&gt;
&lt;h3 id=&quot;1-webfilter-annotation&quot;&gt;1. @WebFilter annotation&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;WebFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;urlPatterns&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;/api/*&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;initParams&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;WebInitParam&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;level&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;value&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;DEBUG&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LogFilter&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Filter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { ... }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-webxml&quot;&gt;2. web.xml&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;filter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;filter-name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;logFilter&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;filter-name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;filter-class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;com.example.LogFilter&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;filter-class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;filter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;filter-mapping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;filter-name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;logFilter&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;filter-name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;url-pattern&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;/api/*&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;url-pattern&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;filter-mapping&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;3-spring-boot-filterregistrationbean&quot;&gt;3. Spring Boot FilterRegistrationBean&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Configuration&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; FilterConfig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Bean&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; FilterRegistrationBean&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;LogFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;logFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        FilterRegistrationBean&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;LogFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; reg &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; FilterRegistrationBean&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        reg.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LogFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        reg.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;addUrlPatterns&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;/api/*&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        reg.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setOrder&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 낮을수록 먼저&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; reg;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;순서 제어가 필요하면 &lt;code&gt;FilterRegistrationBean&lt;/code&gt; 권장. &lt;code&gt;@Component&lt;/code&gt; 로 등록하면 Spring Boot 가 자동 매핑하지만 순서를 제어하기 어렵다.&lt;/p&gt;
&lt;h2 id=&quot;흔한-패턴&quot;&gt;흔한 패턴&lt;/h2&gt;
&lt;h3 id=&quot;인증&quot;&gt;인증&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; doFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ServletRequest req, ServletResponse resp, FilterChain chain) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    HttpServletRequest http &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (HttpServletRequest) req;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    String token &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; http.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getHeader&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Authorization&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (token &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;jwtVerifier.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;verify&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(token)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        ((HttpServletResponse) resp).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sendError&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;401&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    chain.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;doFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(req, resp);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;cors&quot;&gt;CORS&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; doFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ServletRequest req, ServletResponse resp, FilterChain chain) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    HttpServletResponse http &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (HttpServletResponse) resp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    http.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setHeader&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Access-Control-Allow-Origin&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;https://app.example.com&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    http.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setHeader&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Access-Control-Allow-Methods&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;GET, POST, PUT, DELETE&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    http.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setHeader&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Access-Control-Allow-Headers&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Authorization, Content-Type&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;OPTIONS&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;equalsIgnoreCase&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(((HttpServletRequest) req).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getMethod&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;())) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        http.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setStatus&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;204&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    chain.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;doFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(req, resp);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;문자-인코딩&quot;&gt;문자 인코딩&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; doFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ServletRequest req, ServletResponse resp, FilterChain chain) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;setCharacterEncoding&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;UTF-8&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    chain.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;doFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(req, resp);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Spring Boot 는 &lt;code&gt;CharacterEncodingFilter&lt;/code&gt; 가 기본 등록돼 있음.&lt;/p&gt;
&lt;h3 id=&quot;응답-압축--캐싱-wrapper&quot;&gt;응답 압축 / 캐싱 (wrapper)&lt;/h3&gt;
&lt;p&gt;응답을 가로채려면 &lt;code&gt;HttpServletResponseWrapper&lt;/code&gt; 로 감싸기:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; doFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ServletRequest req, ServletResponse resp, FilterChain chain) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ContentCachingResponseWrapper wrapper &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ContentCachingResponseWrapper&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;((HttpServletResponse) resp);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    chain.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;doFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(req, wrapper);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    byte&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] body &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; wrapper.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getContentAsByteArray&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // 로깅, 압축, 변환 ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    wrapper.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;copyBodyToResponse&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 실제 응답으로 복사&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;요청도 마찬가지: &lt;code&gt;ContentCachingRequestWrapper&lt;/code&gt; 로 본문을 캐싱해야 logging filter + controller 가 모두 읽을 수 있다.&lt;/p&gt;
&lt;h2 id=&quot;onceperrequestfilter-spring&quot;&gt;OncePerRequestFilter (Spring)&lt;/h2&gt;
&lt;p&gt;Servlet spec 에선 &lt;code&gt;forward&lt;/code&gt; / &lt;code&gt;include&lt;/code&gt; / &lt;code&gt;async dispatch&lt;/code&gt; 시 filter chain 이 &lt;strong&gt;다시 실행&lt;/strong&gt; 될 수 있다. 인증 filter 가 2 번 돌면 안 되는데.&lt;/p&gt;
&lt;p&gt;Spring 의 &lt;code&gt;OncePerRequestFilter&lt;/code&gt; 가 이 문제를 해결:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; JwtFilter&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; OncePerRequestFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    protected&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; doFilterInternal&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(HttpServletRequest &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, HttpServletResponse &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;resp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, FilterChain &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;chain&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            throws&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ServletException, IOException {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // 요청당 정확히 1회만 실행 보장&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        chain.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;doFilter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(req, resp);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;내부적으로 request attribute 에 &lt;code&gt;alreadyFilteredAttributeName&lt;/code&gt; 플래그를 두고 중복 실행을 차단. &lt;strong&gt;Spring 환경에선 거의 항상 이걸 상속하는 게 안전&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;filter-vs-handlerinterceptor-vs-aop&quot;&gt;Filter vs HandlerInterceptor vs AOP&lt;/h2&gt;















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;항목&lt;/th&gt;&lt;th&gt;Filter&lt;/th&gt;&lt;th&gt;HandlerInterceptor&lt;/th&gt;&lt;th&gt;AOP @Around&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;실행 위치&lt;/td&gt;&lt;td&gt;servlet 컨테이너&lt;/td&gt;&lt;td&gt;DispatcherServlet 내부&lt;/td&gt;&lt;td&gt;Bean 메서드 호출&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Spring context 접근&lt;/td&gt;&lt;td&gt;등록 시 의존성 주입 가능&lt;/td&gt;&lt;td&gt;Spring Bean 으로 자연 통합&lt;/td&gt;&lt;td&gt;Spring Bean 만 적용&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;handler 정보 접근&lt;/td&gt;&lt;td&gt;불가&lt;/td&gt;&lt;td&gt;가능 (&lt;code&gt;Object handler&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;proxy target 메서드&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;응답 변환 가능&lt;/td&gt;&lt;td&gt;가능 (wrapper 로)&lt;/td&gt;&lt;td&gt;postHandle 에서 ModelAndView&lt;/td&gt;&lt;td&gt;메서드 반환값 변형&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;예외 처리&lt;/td&gt;&lt;td&gt;직접 try/catch&lt;/td&gt;&lt;td&gt;afterCompletion 의 &lt;code&gt;ex&lt;/code&gt;&lt;/td&gt;&lt;td&gt;throwing advice&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;적용 범위&lt;/td&gt;&lt;td&gt;URL 패턴&lt;/td&gt;&lt;td&gt;URL 패턴 + handler&lt;/td&gt;&lt;td&gt;pointcut (메서드/클래스)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;규칙: HTTP 레이어 (인증, CORS, 압축, 로깅) = Filter, MVC handler 정보 필요 = Interceptor, 서비스 메서드 횡단 관심사 = AOP.&lt;/p&gt;
&lt;h2 id=&quot;함정과-베스트-프랙티스&quot;&gt;함정과 베스트 프랙티스&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;항상 &lt;code&gt;OncePerRequestFilter&lt;/code&gt; (Spring 환경)&lt;/strong&gt;: forward/include 중복 방지&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;순서 제어 명시적으로&lt;/strong&gt;: &lt;code&gt;FilterRegistrationBean.setOrder()&lt;/code&gt; 또는 &lt;code&gt;@Order&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;chain.doFilter 누락 방지&lt;/strong&gt;: 중단 의도가 아니면 반드시 호출&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;try/finally 패턴&lt;/strong&gt;: ThreadLocal set/remove, 시간 측정 등은 finally 에서&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;응답 commit 후 헤더 변경 불가&lt;/strong&gt;: filter 후처리에서 헤더 추가하려면 응답이 아직 commit 전이어야&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;본문 wrapper 는 메모리 비용&lt;/strong&gt;: 큰 body 전체 캐싱은 OOM 위험&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[java-servlet-api]]&lt;/li&gt;
&lt;li&gt;[[java-servlet-lifecycle]]&lt;/li&gt;
&lt;li&gt;[[spring-handler-interceptor]]&lt;/li&gt;
&lt;li&gt;[[spring-aop]]&lt;/li&gt;
&lt;li&gt;[[spring-security]]&lt;/li&gt;
&lt;li&gt;[[spring-dispatcher-servlet]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>servlet</category><category>filter</category><category>http</category><author>koa (김신건)</author></item><item><title>[Java] Servlet 생명주기</title><link>https://shinkeonkim.com/wiki/java/java-servlet-lifecycle/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-servlet-lifecycle/</guid><pubDate>Sun, 21 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;Servlet 은 &lt;strong&gt;컨테이너 (Tomcat / Jetty / Undertow) 가 생성, 호출, 소멸시키는 객체&lt;/strong&gt;. 개발자는 인터페이스 메서드만 구현하고 인스턴스 관리는 일체 안 한다.&lt;/p&gt;
&lt;p&gt;핵심 메서드 3 가지:&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;메서드&lt;/th&gt;&lt;th&gt;호출 시점&lt;/th&gt;&lt;th&gt;호출 횟수&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;init(ServletConfig)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;첫 요청 도착 시 (lazy) 또는 컨테이너 시작 시 (eager)&lt;/td&gt;&lt;td&gt;인스턴스당 1회&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;service(req, resp)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;매 HTTP 요청&lt;/td&gt;&lt;td&gt;요청마다 1회, 멀티스레드로 동시 호출&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;destroy()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;컨테이너 종료 또는 hot reload 시&lt;/td&gt;&lt;td&gt;인스턴스당 1회&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;code&gt;HttpServlet&lt;/code&gt; 은 &lt;code&gt;service()&lt;/code&gt; 를 오버라이드해 HTTP 메서드별로 &lt;code&gt;doGet&lt;/code&gt; / &lt;code&gt;doPost&lt;/code&gt; / &lt;code&gt;doPut&lt;/code&gt; 등에 분기.&lt;/p&gt;
&lt;h2 id=&quot;인스턴스-수-1&quot;&gt;인스턴스 수: 1&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;기본적으로 servlet 클래스당 인스턴스 1개&lt;/strong&gt;. 모든 요청이 같은 인스턴스의 &lt;code&gt;service()&lt;/code&gt; 를 동시 호출. 그래서:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; BrokenServlet&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; HttpServlet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; String currentUser;  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ 멀티스레드 공유 = race condition&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    protected&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; doGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(HttpServletRequest &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, HttpServletResponse &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;resp&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        currentUser &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getRemoteUser&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        respondWithGreeting&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(currentUser);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 다른 요청이 덮어쓸 수 있음&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;규칙&lt;/strong&gt;: 인스턴스 필드 = 불변 의존성만 (logger, config). 요청별 데이터는 메서드 로컬 변수에.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SingleThreadModel&lt;/code&gt; 마커 인터페이스는 Servlet 2.4 부터 deprecated. 대신 thread-safe 하게 작성하거나 ThreadLocal 사용 ([[java-threadlocal]]).&lt;/p&gt;
&lt;p&gt;실제 라이프사이클 로그 출력:&lt;/p&gt;
&lt;!-- mdx-component: CodeWithOutput --&gt;
&lt;p&gt;&lt;code&gt;AtomicLong&lt;/code&gt; 같은 thread-safe 필드만 안전하다. worker thread 가 같은 인스턴스를 공유한다는 사실에 주목.&lt;/p&gt;
&lt;h2 id=&quot;init-lazy-vs-eager&quot;&gt;init: lazy vs eager&lt;/h2&gt;
&lt;p&gt;기본은 &lt;strong&gt;lazy&lt;/strong&gt;: 첫 요청이 와야 인스턴스 생성 + &lt;code&gt;init()&lt;/code&gt; 호출. 첫 요청이 느려진다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;load-on-startup&lt;/code&gt; 으로 eager:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;WebServlet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;urlPatterns&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;/api/*&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;loadOnStartup&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ApiServlet&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; HttpServlet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { ... }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;xml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&amp;#x3C;!-- web.xml --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;servlet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;servlet-name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;api&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;servlet-name&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;servlet-class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;com.example.ApiServlet&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;servlet-class&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;load-on-startup&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;1&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;load-on-startup&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;&amp;#x3C;!-- 숫자 작을수록 먼저 --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;servlet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DB 풀 초기화, 캐시 워밍업 등 무거운 작업을 &lt;code&gt;init()&lt;/code&gt; 에서 한다. &lt;code&gt;init()&lt;/code&gt; 실패 시 &lt;code&gt;ServletException&lt;/code&gt; 던지면 컨테이너는 servlet 을 사용 불가 처리.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; init&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() throws ServletException {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.dataSource &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; createDataSource&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (SQLException &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ServletException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;DB 초기화 실패&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, e);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;service-의-dispatch&quot;&gt;service 의 dispatch&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;HttpServlet.service()&lt;/code&gt; 의 기본 구현:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// HttpServlet (간략화)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; service&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(HttpServletRequest req, HttpServletResponse resp) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    String method &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getMethod&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    switch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (method) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;GET&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    doGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(req, resp); &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;POST&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;   doPost&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(req, resp); &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;PUT&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    doPut&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(req, resp); &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;DELETE&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; doDelete&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(req, resp); &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;HEAD&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;   doHead&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(req, resp); &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;OPTIONS&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; doOptions&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(req, resp); &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        case&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &quot;TRACE&quot;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  doTrace&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(req, resp); &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        default:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; resp.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sendError&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(SC_NOT_IMPLEMENTED);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;직접 &lt;code&gt;service()&lt;/code&gt; 를 오버라이드하면 메서드 분기를 직접 해야 함. 일반적으로는 &lt;code&gt;doX()&lt;/code&gt; 만 오버라이드.&lt;/p&gt;
&lt;h2 id=&quot;destroy&quot;&gt;destroy&lt;/h2&gt;
&lt;p&gt;컨테이너가 servlet 을 제거하기 직전 호출. 진행 중인 요청이 끝날 때까지 기다림 (graceful shutdown).&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; destroy&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (dataSource &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) dataSource.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;close&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    executor.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;shutdown&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;중요한 한계&lt;/strong&gt;: JVM 이 비정상 종료 (kill -9, OOM crash) 되면 &lt;code&gt;destroy()&lt;/code&gt; 호출 안 됨. 영속적 cleanup 은 외부 메커니즘 (DB transaction commit, file flush) 에 의존하지 말 것.&lt;/p&gt;
&lt;h2 id=&quot;컨테이너의-인스턴스-관리&quot;&gt;컨테이너의 인스턴스 관리&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;컨테이너 시작&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  └─ load-on-startup servlet 인스턴스화&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       └─ init() 호출&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;요청 도착&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ├─ 첫 요청이면 lazy servlet 인스턴스화 + init()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  └─ thread pool 에서 worker thread 가져옴&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       └─ servlet.service(req, resp)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            └─ doGet/doPost/...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;요청 처리 중&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  └─ 같은 servlet 인스턴스에 동시 호출 가능 (다른 worker thread 에서)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;컨테이너 종료 / 재배포&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ├─ 신규 요청 거부&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ├─ 진행 중 요청 완료 대기 (timeout)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  └─ servlet.destroy() → GC&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tomcat 의 &lt;code&gt;Connector&lt;/code&gt; + &lt;code&gt;Executor&lt;/code&gt; 가 worker thread pool 을 관리. 기본 200 개. &lt;code&gt;server.tomcat.threads.max&lt;/code&gt; 로 조정.&lt;/p&gt;
&lt;h2 id=&quot;hot-deploy-와-classloader&quot;&gt;hot deploy 와 ClassLoader&lt;/h2&gt;
&lt;p&gt;Spring Boot DevTools 가 코드 변경 감지 시:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;기존 WebApplicationContext + servlet &lt;code&gt;destroy()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;새 ClassLoader 로 클래스 재로딩&lt;/li&gt;
&lt;li&gt;새 인스턴스 + &lt;code&gt;init()&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이때 &lt;code&gt;init()&lt;/code&gt; / &lt;code&gt;destroy()&lt;/code&gt; 가 빠르고 idempotent 여야 함. 외부 리소스 (DB connection) 누수 주의.&lt;/p&gt;
&lt;h2 id=&quot;비동기-lifecycle&quot;&gt;비동기 lifecycle&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;startAsync()&lt;/code&gt; 호출 시 &lt;code&gt;service()&lt;/code&gt; 반환과 응답 commit 이 분리:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;protected&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; doGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(HttpServletRequest req, HttpServletResponse resp) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    AsyncContext ac &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; req.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;startAsync&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ac.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // 별도 thread 에서 응답 작성&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        respondLater&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ac);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// service() 는 즉시 반환, but 응답은 아직 미완료&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;worker thread 는 풀로 복귀. 응답 완료는 &lt;code&gt;ac.complete()&lt;/code&gt; 호출 시. timeout 도 컨테이너가 관리.&lt;/p&gt;
&lt;h2 id=&quot;함정과-베스트-프랙티스&quot;&gt;함정과 베스트 프랙티스&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;인스턴스 필드 = 불변 의존성만&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;init()&lt;/code&gt; 에서 OOM 위험 작업 (큰 캐시 로드) 주의&lt;/strong&gt;: 컨테이너 시작이 멈춤&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;destroy()&lt;/code&gt; 는 빠르게&lt;/strong&gt;: 응답 안 하면 컨테이너가 강제 종료&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;graceful shutdown&lt;/strong&gt; 은 &lt;code&gt;Tomcat.setAwaitTimeout()&lt;/code&gt; 또는 Spring Boot &lt;code&gt;server.shutdown=graceful&lt;/code&gt; 설정&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;load-on-startup&lt;/strong&gt; 은 정수만 의미 있음. 음수면 lazy 와 동일.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;컨테이너 별 차이&lt;/strong&gt;: Tomcat 은 worker thread pool, Jetty 도 유사, Undertow 는 XNIO 기반 다름.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[java-servlet-api]]&lt;/li&gt;
&lt;li&gt;[[java-servlet-filter]]&lt;/li&gt;
&lt;li&gt;[[java-threadlocal]]&lt;/li&gt;
&lt;li&gt;[[spring-dispatcher-servlet]]&lt;/li&gt;
&lt;li&gt;[[spring-mvc]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>servlet</category><category>lifecycle</category><category>container</category><author>koa (김신건)</author></item><item><title>[Java] ThreadLocal</title><link>https://shinkeonkim.com/wiki/java/java-threadlocal/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-threadlocal/</guid><pubDate>Sun, 21 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ThreadLocal&amp;#x3C;T&gt;&lt;/code&gt; 는 &lt;strong&gt;각 스레드마다 독립된 변수 사본을 가지게 해 주는 컨테이너&lt;/strong&gt;. &lt;code&gt;set/get/remove&lt;/code&gt; 로 접근하며, 한 스레드의 값은 다른 스레드에서 볼 수 없다.&lt;/p&gt;
&lt;p&gt;쓰임은 두 가지: (1) 같은 인스턴스를 여러 스레드가 공유하지만 상태는 격리해야 할 때 (e.g., &lt;code&gt;SimpleDateFormat&lt;/code&gt; 캐싱), (2) 메서드 인자로 전달하기 번거로운 “요청 컨텍스트” 를 호출 스택 전체에 보이게 하고 싶을 때 (e.g., 트랜잭션, 인증 정보).&lt;/p&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;각 스레드가 자신의 &lt;code&gt;ThreadLocalMap&lt;/code&gt; 에만 값을 저장. 다른 스레드는 접근 자체 불가.&lt;/p&gt;
&lt;h2 id=&quot;기본-사용&quot;&gt;기본 사용&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RequestId&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ThreadLocal&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; CURRENT &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ThreadLocal&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(String &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;id&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { CURRENT.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(id); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; String &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; CURRENT.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; clear&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { CURRENT.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 진입점에서 설정&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;RequestId.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;req-123&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    service.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;doWork&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 깊은 호출 스택 어디서든 RequestId.get() 으로 접근&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    RequestId.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;clear&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 반드시 정리&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;실행해 보면 각 스레드가 독립 값을 보유한다:&lt;/p&gt;
&lt;p&gt;&amp;#x3C;CodeWithOutput
language=“java”
outputLanguage=“text”
code={`public class ThreadLocalDemo {
static final ThreadLocal&lt;integer&gt; COUNT = ThreadLocal.withInitial(() -&gt; 0);&lt;/integer&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;public static void main(String[] args) throws InterruptedException {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    Runnable task = () -&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        for (int i = 0; i &amp;#x3C; 3; i++) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;            COUNT.set(COUNT.get() + 1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        System.out.println(Thread.currentThread().getName() + &quot; count=&quot; + COUNT.get());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    Thread t1 = new Thread(task, &quot;A&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    Thread t2 = new Thread(task, &quot;B&quot;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    t1.start(); t2.start();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    t1.join(); t2.join();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;code&gt;}   output={&lt;/code&gt;A count=3
B count=3`}
/&gt;&lt;/p&gt;
&lt;p&gt;각 스레드는 자신의 카운터만 증가. 스레드 간 누수 없음.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;withInitial&lt;/code&gt; 로 lazy 초기값 지정 가능:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ThreadLocal&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;SimpleDateFormat&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; FORMAT &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    ThreadLocal.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;withInitial&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; SimpleDateFormat&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;yyyy-MM-dd&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String today &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; FORMAT.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;format&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Date&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;SimpleDateFormat&lt;/code&gt; 은 thread-safe 하지 않으므로 흔한 패턴.&lt;/p&gt;
&lt;h2 id=&quot;내부-구조&quot;&gt;내부 구조&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ThreadLocal&lt;/code&gt; 값은 &lt;code&gt;ThreadLocal&lt;/code&gt; 인스턴스 자체에 저장되지 않는다. 각 &lt;code&gt;Thread&lt;/code&gt; 객체 안의 &lt;strong&gt;&lt;code&gt;ThreadLocalMap&lt;/code&gt;&lt;/strong&gt; 에 저장된다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Thread A.threadLocals = { ThreadLocal_X: &quot;A 값&quot;, ThreadLocal_Y: 1 }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Thread B.threadLocals = { ThreadLocal_X: &quot;B 값&quot; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ThreadLocal&lt;/code&gt; 인스턴스는 map 의 &lt;strong&gt;key&lt;/strong&gt; 역할. 그래서 같은 &lt;code&gt;ThreadLocal&lt;/code&gt; 변수에 대해 스레드별로 다른 값이 보이는 것.&lt;/p&gt;
&lt;p&gt;map 의 키는 &lt;code&gt;WeakReference&amp;#x3C;ThreadLocal&gt;&lt;/code&gt;. &lt;code&gt;ThreadLocal&lt;/code&gt; 변수 자체가 GC 되면 entry 의 key 가 null 이 되지만, &lt;strong&gt;value 는 strong reference 라 GC 안 됨&lt;/strong&gt;. 이게 누수의 원인.&lt;/p&gt;
&lt;h2 id=&quot;메모리-누수-함정&quot;&gt;메모리 누수 함정&lt;/h2&gt;
&lt;p&gt;스레드 풀 환경에서 흔히 발생:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 잘못된 패턴&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ExecutorService pool &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Executors.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;newFixedThreadPool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;pool.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;submit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    BIG_OBJECT.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; byte&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;100_000_000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 100 MB 할당&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    doWork&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // remove() 안 함&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;스레드가 풀에 반환돼도 &lt;code&gt;ThreadLocalMap&lt;/code&gt; 은 그대로. 다음 작업이 와도 그 100 MB 가 계속 살아있다. 10 개 스레드 풀이면 최악의 경우 1 GB 가 유지됨.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;규칙: 진입점에서 &lt;code&gt;try { set(...); ... } finally { remove(); }&lt;/code&gt; 패턴 강제&lt;/strong&gt;. Web 프레임워크들이 servlet filter / interceptor 로 처리해 주는 이유.&lt;/p&gt;
&lt;h2 id=&quot;inheritablethreadlocal&quot;&gt;InheritableThreadLocal&lt;/h2&gt;
&lt;p&gt;자식 스레드가 부모의 값을 상속:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;InheritableThreadLocal&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; trace &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; InheritableThreadLocal&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;trace.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;trace-1&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Thread&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(trace.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// &quot;trace-1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;중요한 한계&lt;/strong&gt;: &lt;code&gt;Thread&lt;/code&gt; 생성 시점에 값이 복사된다. 스레드 풀처럼 스레드를 재사용하면 풀에 들어갈 때 한 번만 복사되고, 이후 작업에서는 stale 한 부모 값이 그대로. 풀 환경에선 거의 무용지물.&lt;/p&gt;
&lt;p&gt;Spring 의 &lt;code&gt;TaskDecorator&lt;/code&gt; 로 매 작업마다 복사하는 패턴이 일반적.&lt;/p&gt;
&lt;h2 id=&quot;scopedvalue-jdk-21&quot;&gt;ScopedValue (JDK 21+)&lt;/h2&gt;
&lt;p&gt;ThreadLocal 의 함정을 해결한 &lt;strong&gt;불변, 스코프 한정&lt;/strong&gt; 대안:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ScopedValue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; CURRENT_USER &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ScopedValue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;newInstance&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ScopedValue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;where&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(CURRENT_USER, alice)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // 이 블록 안에서만 CURRENT_USER.get() == alice&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        service.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 블록 종료 = 자동 해제, 누수 불가능&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;특징:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;불변&lt;/strong&gt;: set 으로 덮어쓸 수 없음 (rebinding 만 가능, 새 스코프 안에서)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;자동 정리&lt;/strong&gt;: try/finally 불필요&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;virtual thread 친화적&lt;/strong&gt;: 가벼움 (ThreadLocal 은 virtual thread 마다 map 생성 비용)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;JDK 25 에서도 preview 단계 (2026 기준). 정식 stable 화 진행 중.&lt;/p&gt;
&lt;h2 id=&quot;spring-활용&quot;&gt;Spring 활용&lt;/h2&gt;
&lt;p&gt;Spring 은 ThreadLocal 을 광범위하게 사용. 주요 위치:&lt;/p&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;컴포넌트&lt;/th&gt;&lt;th&gt;저장 대상&lt;/th&gt;&lt;th&gt;설정/해제 시점&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;RequestContextHolder&lt;/code&gt;&lt;/td&gt;&lt;td&gt;HTTP 요청/응답 attributes&lt;/td&gt;&lt;td&gt;&lt;code&gt;RequestContextFilter&lt;/code&gt;, &lt;code&gt;DispatcherServlet&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;LocaleContextHolder&lt;/code&gt;&lt;/td&gt;&lt;td&gt;현재 요청의 locale&lt;/td&gt;&lt;td&gt;&lt;code&gt;LocaleResolver&lt;/code&gt; 가 갱신&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;TransactionSynchronizationManager&lt;/code&gt;&lt;/td&gt;&lt;td&gt;현재 트랜잭션 자원 (Connection 등)&lt;/td&gt;&lt;td&gt;&lt;code&gt;@Transactional&lt;/code&gt; 진입/종료&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;SecurityContextHolder&lt;/code&gt; (Spring Security)&lt;/td&gt;&lt;td&gt;인증된 &lt;code&gt;Authentication&lt;/code&gt; 객체&lt;/td&gt;&lt;td&gt;&lt;code&gt;SecurityContextPersistenceFilter&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;code&gt;@Async&lt;/code&gt; 메서드는 별도 스레드에서 실행되므로 위 ThreadLocal 이 자동 전파되지 않음. 해결책은 &lt;code&gt;TaskDecorator&lt;/code&gt; 로 컨텍스트를 복사하거나 &lt;code&gt;setRequestAttributes(attrs, inheritable=true)&lt;/code&gt; 옵션 사용. [[spring-request-context]] 참고.&lt;/p&gt;
&lt;h2 id=&quot;베스트-프랙티스&quot;&gt;베스트 프랙티스&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;private static final&lt;/code&gt; 로 선언 (인스턴스마다 만들면 누수 가속)&lt;/li&gt;
&lt;li&gt;반드시 &lt;code&gt;try { set; ... } finally { remove; }&lt;/code&gt; 패턴&lt;/li&gt;
&lt;li&gt;프레임워크가 관리해 주는 ThreadLocal 은 직접 건드리지 말 것&lt;/li&gt;
&lt;li&gt;스레드 풀에서 쓸 때 더 조심&lt;/li&gt;
&lt;li&gt;JDK 21+ 신규 코드에선 &lt;code&gt;ScopedValue&lt;/code&gt; 우선 검토&lt;/li&gt;
&lt;li&gt;virtual thread 사용 시 &lt;code&gt;ThreadLocal&lt;/code&gt; 남용 피하기 (수백만 개 가능 = 누수 폭발)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;관련-위키&quot;&gt;관련 위키&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[java-volatile]]&lt;/li&gt;
&lt;li&gt;[[java-atomic-integer]]&lt;/li&gt;
&lt;li&gt;[[java-reentrant-lock]]&lt;/li&gt;
&lt;li&gt;[[spring-request-context]]&lt;/li&gt;
&lt;li&gt;[[spring-security]]&lt;/li&gt;
&lt;li&gt;[[spring-transaction]]&lt;/li&gt;
&lt;li&gt;[[spring-scheduling-async]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>concurrency</category><category>threadlocal</category><category>memory</category><author>koa (김신건)</author></item><item><title>[Java] ArrayBlockingQueue</title><link>https://shinkeonkim.com/wiki/java/java-arrayblockingqueue/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-arrayblockingqueue/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.concurrent.ArrayBlockingQueue&amp;#x3C;E&gt;&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;고정 크기 원형 배열&lt;/strong&gt; 기반의 [[BlockingQueue]]. 생성 시 capacity 를 지정해야 하고 그 이상 늘어나지 않는다.&lt;/p&gt;
&lt;p&gt;내부에 &lt;strong&gt;단일 [[ReentrantLock]]&lt;/strong&gt; 을 사용 (head/tail 공유). 동시 throughput 은 [[LinkedBlockingQueue]] 보다 낮을 수 있지만 메모리 사용량이 예측 가능하고 GC 압력이 작다.&lt;/p&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;내부-구조&quot;&gt;내부 구조&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArrayBlockingQueue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; ... {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] items;          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 원형 배열&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; takeIndex;                  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// head&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; putIndex;                   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// tail (next slot)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; count;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ReentrantLock lock;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Condition notEmpty;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Condition notFull;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;notEmpty&lt;/code&gt;, &lt;code&gt;notFull&lt;/code&gt; 두 [[ReentrantLock]] &lt;code&gt;Condition&lt;/code&gt; 을 사용. take 가 비어 있으면 notEmpty 에서 대기, put 이 가득 차면 notFull 에서 대기.&lt;/p&gt;
&lt;h2 id=&quot;동작&quot;&gt;동작&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(E e) throws InterruptedException {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    lock.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;lockInterruptibly&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; items.length) notFull.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();      &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 가득 차면 대기&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        enqueue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(e);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        notEmpty.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;signal&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                                    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// take 대기자 깨움&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { lock.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unlock&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; E &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;take&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() throws InterruptedException {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    lock.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;lockInterruptibly&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) notEmpty.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 비어 있으면 대기&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        E e &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; dequeue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        notFull.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;signal&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                                     &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// put 대기자 깨움&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; e;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { lock.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unlock&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;복잡도&quot;&gt;복잡도&lt;/h2&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;작업&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;시간&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;put&lt;/code&gt;, &lt;code&gt;take&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;offer&lt;/code&gt;, &lt;code&gt;poll&lt;/code&gt;, &lt;code&gt;peek&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;contains&lt;/code&gt;, &lt;code&gt;remove(Object)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;순회&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n), weakly consistent&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;arrayblockingqueue-vs-linkedblockingqueue&quot;&gt;ArrayBlockingQueue vs LinkedBlockingQueue&lt;/h2&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;항목&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;ArrayBlockingQueue&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;LinkedBlockingQueue&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;크기&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;항상 bounded&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;optionally bounded&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;백킹&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;원형 배열&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;linked list&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;락&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;단일&lt;/strong&gt; ReentrantLock&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;takeLock + putLock 분리&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;동시 throughput&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;낮음 (락 경합)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;높음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;메모리 / 원소&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;슬롯 1개&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;노드 객체 1개&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;GC 압력&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;작음 (배열 고정)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;큼 (노드 생성/소멸)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;공정성 옵션&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✗&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
메모리 예측이 중요한 환경, 또는 capacity 가 작은 경우 ArrayBlockingQueue 가 자연스럽다. 대량 throughput 이 필요하면 LinkedBlockingQueue.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;사용-예&quot;&gt;사용 예&lt;/h2&gt;
&lt;h3 id=&quot;bounded-생산자-소비자&quot;&gt;bounded 생산자-소비자&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;BlockingQueue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; queue &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayBlockingQueue&amp;#x3C;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Producer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Thread&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (running) queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;create&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Consumer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Thread&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (running) &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;take&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[BlockingQueue]]&lt;/li&gt;
&lt;li&gt;[[LinkedBlockingQueue]]&lt;/li&gt;
&lt;li&gt;[[ReentrantLock]]&lt;/li&gt;
&lt;li&gt;[[Blocking]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>concurrent</category><category>queue</category><category>blocking</category><category>bounded</category><author>koa (김신건)</author></item><item><title>[Java] ArrayDeque</title><link>https://shinkeonkim.com/wiki/java/java-arraydeque/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-arraydeque/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.ArrayDeque&amp;#x3C;E&gt;&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;원형 배열 (circular buffer)&lt;/strong&gt; 기반의 [[Deque]] 구현. JDK 1.6 도입.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Stack&lt;/code&gt; 으로 쓰면 &lt;code&gt;java.util.Stack&lt;/code&gt; 보다 빠르고, &lt;code&gt;Queue&lt;/code&gt; 로 쓰면 [[LinkedList]] 보다 빠르다. &lt;strong&gt;Stack / Queue / Deque 가 필요할 때 거의 항상 첫 번째 선택&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;내부-구조&quot;&gt;내부 구조&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArrayDeque&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AbstractCollection&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Deque&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Cloneable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Serializable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    transient&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] elements;       &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 백킹 배열&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    transient&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; head;                &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// head 인덱스&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    transient&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tail;                &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// tail 인덱스 (next slot)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;원형 배열 (circular array) 방식.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;head&lt;/strong&gt; 와 &lt;strong&gt;tail&lt;/strong&gt; 인덱스를 따로 관리&lt;/li&gt;
&lt;li&gt;배열의 끝에 도달하면 다시 0 으로 (modular arithmetic)&lt;/li&gt;
&lt;li&gt;가득 차면 2 배로 grow&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;초기 (size 8):  [_ _ _ _ _ _ _ _]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                 ↑head=tail=0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;addLast: a, b, c&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        [a b c _ _ _ _ _]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;         ↑head    ↑tail=3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;addFirst: x&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        [a b c _ _ _ _ x]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                       ↑head=7  tail=3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;수정된 인덱스 = (i + length) % length&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;복잡도&quot;&gt;복잡도&lt;/h2&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;작업&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;시간&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;addFirst&lt;/code&gt;, &lt;code&gt;addLast&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;amortized O(1)&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;removeFirst&lt;/code&gt;, &lt;code&gt;removeLast&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(1)&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;peek*&lt;/code&gt;, &lt;code&gt;getFirst&lt;/code&gt;, &lt;code&gt;getLast&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;contains&lt;/code&gt;, &lt;code&gt;remove(Object)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;임의 인덱스 접근&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;불가 (List 가 아니므로)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;code&gt;amortized&lt;/code&gt; 인 이유는 가득 찼을 때 2 배 grow + copy 비용 때문. 평균은 O(1).&lt;/p&gt;
&lt;h2 id=&quot;linkedlist-vs-arraydeque&quot;&gt;LinkedList vs ArrayDeque&lt;/h2&gt;


















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;항목&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;LinkedList&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;ArrayDeque&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;백킹&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;linked nodes&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;원형 배열&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;메모리 / 원소&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;노드 헤더 + 두 포인터 (~32B)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;슬롯 1 개 (4-8B)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;캐시 친화&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✓&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;addFirst / addLast&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;O(1)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;amortized O(1)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;null 허용&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✗&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;List 가능&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✓ (인덱스 O(n))&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✗&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Deque 가능&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✓&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;실측 속도&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;느림&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;빠름&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;null 거부와 List 미구현이 단점이지만, 그 외에는 모든 면에서 LinkedList 보다 우월.&lt;/p&gt;
&lt;h2 id=&quot;stack-사용-예&quot;&gt;Stack 사용 예&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Deque&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; stack &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayDeque&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;stack.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);              &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// head 쪽에 push&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;stack.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;stack.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;stack.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;peek&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();               &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;stack.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;pop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Deque&amp;#x3C;E&gt; stack = new ArrayDeque&amp;#x3C;&gt;()&lt;/code&gt; 패턴이 [[java] Vector]] 기반 &lt;code&gt;Stack&amp;#x3C;E&gt;&lt;/code&gt; 보다 두세 배 빠르다.&lt;/p&gt;
&lt;h2 id=&quot;queue-사용-예&quot;&gt;Queue 사용 예&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Queue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; queue &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayDeque&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;offer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(task1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;offer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(task2);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Task t &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;poll&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();      &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// task1 (FIFO)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;함정&quot;&gt;함정&lt;/h2&gt;
&lt;h3 id=&quot;1-null-비허용&quot;&gt;1. null 비허용&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Deque&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; dq &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayDeque&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;dq.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// NullPointerException&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이유: poll/peek 이 null 을 “비어 있음” 신호로 쓰는 의미와 충돌.&lt;/p&gt;
&lt;h3 id=&quot;2-thread-safe-가-아님&quot;&gt;2. thread-safe 가 아님&lt;/h3&gt;
&lt;p&gt;[[ConcurrentLinkedDeque]] 또는 &lt;code&gt;LinkedBlockingDeque&lt;/code&gt; 사용.&lt;/p&gt;
&lt;h3 id=&quot;3-iterator-는-fail-fast-iterator&quot;&gt;3. iterator 는 [[fail-fast iterator]]&lt;/h3&gt;
&lt;p&gt;순회 중 수정 시 CME.&lt;/p&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[Object]]&lt;/li&gt;
&lt;li&gt;[[Iterable]]&lt;/li&gt;
&lt;li&gt;[[Collection]]&lt;/li&gt;
&lt;li&gt;[[Queue]]&lt;/li&gt;
&lt;li&gt;[[Deque]]&lt;/li&gt;
&lt;li&gt;[[LinkedList]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentLinkedDeque]]&lt;/li&gt;
&lt;li&gt;[[fail-fast iterator]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>collection</category><category>deque</category><category>queue</category><category>stack</category><category>array</category><author>koa (김신건)</author></item><item><title>[Java] ArrayList</title><link>https://shinkeonkim.com/wiki/java/java-arraylist/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-arraylist/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.ArrayList&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;동적 배열 (dynamic array)&lt;/strong&gt; 로 구현된 [[List]]. 내부적으로 &lt;code&gt;Object[]&lt;/code&gt; 를 들고 다니며, 용량이 부족해지면 새 배열로 옮긴다.&lt;/p&gt;
&lt;p&gt;Java 의 가장 흔한 컬렉션 구현체. 인덱스 기반 접근이 압도적으로 빠르고, 캐시 친화적이라 LinkedList 보다 실측이 빠른 경우가 대부분이다.&lt;/p&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;내부-구조&quot;&gt;내부 구조&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArrayList&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AbstractList&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;, ... {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    transient&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] elementData;   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 백킹 배열&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; size;                 &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 실제 원소 수&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; DEFAULT_CAPACITY &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 10&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;세 개의 핵심 변수.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;elementData&lt;/code&gt;&lt;/strong&gt;: 실제 데이터가 들어있는 배열. 길이가 곧 capacity.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;size&lt;/code&gt;&lt;/strong&gt;: 사용 중인 슬롯 수. &lt;code&gt;size &amp;#x3C;= elementData.length&lt;/code&gt; 가 항상 성립.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;DEFAULT_CAPACITY&lt;/code&gt;&lt;/strong&gt;: 첫 add 시 할당되는 초기 크기 (10).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;빈-arraylist-의-lazy-초기화&quot;&gt;빈 ArrayList 의 lazy 초기화&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;();  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// elementData = {}, 빈 배열&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                              &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 이 순간 처음으로 길이 10 배열 할당&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;new ArrayList&amp;#x3C;&gt;()&lt;/code&gt; 만 호출했을 때는 실제 배열을 만들지 않는다. 첫 add 에서 비로소 길이 10 의 배열이 잡힌다. &lt;strong&gt;메모리 절약을 위한 lazy 전략.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;용량-확장-grow&quot;&gt;용량 확장 (&lt;code&gt;grow()&lt;/code&gt;)&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;size == elementData.length&lt;/code&gt; 인 상태에서 add 가 호출되면 새 배열을 만들고 옮긴다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;grow&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; minCapacity) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; oldCapacity &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; elementData.length;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; newCapacity &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArraysSupport.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;newLength&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        oldCapacity,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        minCapacity &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; oldCapacity,    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 최소 증가량&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        oldCapacity &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;              // 선호 증가량 = 50%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; elementData &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Arrays.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;copyOf&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(elementData, newCapacity);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;기본 정책: 1.5 배&lt;/strong&gt; (&lt;code&gt;oldCapacity + oldCapacity &gt;&gt; 1&lt;/code&gt;). 즉 10 → 15 → 22 → 33 → 49 → 73 → …&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
미리 크기를 알면 &lt;strong&gt;&lt;code&gt;new ArrayList&amp;#x3C;&gt;(initialCapacity)&lt;/code&gt;&lt;/strong&gt; 로 생성. 매 &lt;code&gt;grow()&lt;/code&gt; 마다 &lt;code&gt;Arrays.copyOf&lt;/code&gt; (= O(n) 복사) 가 발생하므로, 큰 데이터를 채울 때 차이가 크다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;주요-연산-비용&quot;&gt;주요 연산 비용&lt;/h2&gt;























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;메서드&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;시간 복잡도&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;설명&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;get(int i)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(1)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;elementData[i]&lt;/code&gt; 직접 접근&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;set(int i, E e)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(1)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;인덱스 자리만 교체&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;add(E e)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;amortized O(1)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;size 슬롯에 대입, capacity 부족하면 1.5x 확장&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;add(int i, E e)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;i 이후 원소를 모두 한 칸씩 오른쪽으로 shift&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;remove(int i)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;i 이후 원소를 모두 왼쪽으로 shift&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;remove(Object o)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;indexOf 검색 + shift&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;contains(Object o)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;선형 검색&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;indexOf(Object o)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;선형 검색&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;size()&lt;/code&gt;, &lt;code&gt;isEmpty()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(1)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;size 필드&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;amortized-o1-의-의미&quot;&gt;amortized O(1) 의 의미&lt;/h3&gt;
&lt;p&gt;매 add 가 O(1) 이 아니라 &lt;strong&gt;평균적으로&lt;/strong&gt; O(1) 이라는 뜻. n 개 원소를 추가하는 비용을 따져보면:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;용량 확장 비용 합 = 1 + 1.5 + 2.25 + ... ≈ 3n (등비급수 합 ≤ n / (1-1.5/2.25) ≈ 3n)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;총 비용 = n (단순 대입) + 3n (확장) ≈ 4n&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;평균 = O(1)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;함정&quot;&gt;함정&lt;/h2&gt;
&lt;h3 id=&quot;1-removeint-vs-removeobject-모호성&quot;&gt;1. &lt;code&gt;remove(int)&lt;/code&gt; vs &lt;code&gt;remove(Object)&lt;/code&gt; 모호성&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;List&amp;#x3C;Integer&gt;&lt;/code&gt; 에 대해서는 둘이 다른 의미.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;(List.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;30&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 인덱스 1 의 원소 제거 → [10, 30]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Integer.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;valueOf&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)); &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 값 1 을 찾아서 제거 → 변화 없음 (1 이 없음)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;오토박싱이 위 둘을 헷갈리게 만든다. 명시적으로 &lt;code&gt;Integer.valueOf(x)&lt;/code&gt; 를 권장.&lt;/p&gt;
&lt;h3 id=&quot;2-fail-fast-iterator&quot;&gt;2. [[fail-fast iterator]]&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;(List.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (Integer x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ConcurrentModificationException&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;iterator 의 &lt;code&gt;expectedModCount&lt;/code&gt; 가 &lt;code&gt;ArrayList.modCount&lt;/code&gt; 와 다르면 즉시 예외. 단일 스레드여도 발생.&lt;/p&gt;
&lt;h3 id=&quot;3-sublist-는-뷰일-뿐&quot;&gt;3. &lt;code&gt;subList()&lt;/code&gt; 는 뷰일 뿐&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;(List.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; sub &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;subList&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// [2, 3, 4]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sub.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;99&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// sub = [99, 3, 4]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// list 는?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(list);                &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// [1, 99, 3, 4, 5] ← 원본도 바뀐다&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;독립 사본이 필요하면 &lt;code&gt;new ArrayList&amp;#x3C;&gt;(sub)&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;4-thread-safe-가-아니다&quot;&gt;4. thread-safe 가 아니다&lt;/h3&gt;
&lt;p&gt;여러 스레드가 동시에 수정하면 데이터 손상, 무한 루프, &lt;code&gt;ArrayIndexOutOfBoundsException&lt;/code&gt; 가 발생할 수 있다. 동시성이 필요하면 [[CopyOnWriteArrayList]] 또는 &lt;code&gt;Collections.synchronizedList&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;메모리-사용량&quot;&gt;메모리 사용량&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;객체 헤더 (~16B) + &lt;code&gt;Object[]&lt;/code&gt; 참조 (4-8B) + &lt;code&gt;size&lt;/code&gt; (4B) + &lt;code&gt;modCount&lt;/code&gt; (4B) → 약 32-40B&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;elementData&lt;/code&gt;&lt;/strong&gt;: capacity 만큼의 참조 슬롯 (4-8B × capacity)&lt;/li&gt;
&lt;li&gt;비어있는 슬롯 &lt;code&gt;(capacity - size)&lt;/code&gt; 도 메모리 차지. &lt;code&gt;trimToSize()&lt;/code&gt; 로 회수 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ArrayList&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;); list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 998 슬롯이 null 로 낭비됨&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;trimToSize&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// elementData = new Object[2]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;언제-arraylist-가-답인가&quot;&gt;언제 ArrayList 가 답인가&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;인덱스 접근이 자주 일어남&lt;/strong&gt; (랜덤 read)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;끝에 추가가 대부분&lt;/strong&gt; (스택, 누적 버퍼)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;이미 정렬돼서 보관&lt;/strong&gt;, 이진 탐색 (&lt;code&gt;Collections.binarySearch&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;단일 스레드 또는 외부 동기화&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;언제-다른-구현이-더-나은가&quot;&gt;언제 다른 구현이 더 나은가&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;앞/중간 삽입·삭제가 빈번 + 인덱스 접근 거의 없음&lt;/strong&gt; → [[LinkedList]] (드물게)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;수정이 거의 없는 공유 데이터&lt;/strong&gt; → [[CopyOnWriteArrayList]]&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;불변&lt;/strong&gt; → &lt;code&gt;List.of(...)&lt;/code&gt; / &lt;code&gt;List.copyOf(...)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[Object]]&lt;/li&gt;
&lt;li&gt;[[Iterable]]&lt;/li&gt;
&lt;li&gt;[[Collection]]&lt;/li&gt;
&lt;li&gt;[[List]]&lt;/li&gt;
&lt;li&gt;[[LinkedList]]&lt;/li&gt;
&lt;li&gt;[[Vector]]&lt;/li&gt;
&lt;li&gt;[[CopyOnWriteArrayList]]&lt;/li&gt;
&lt;li&gt;[[fail-fast iterator]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentModificationException]]&lt;/li&gt;
&lt;li&gt;Joshua Bloch, &lt;em&gt;Effective Java&lt;/em&gt; (3rd ed.), Item 28&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>collection</category><category>data-structure</category><category>list</category><category>array</category><author>koa (김신건)</author></item><item><title>[Java] AtomicInteger</title><link>https://shinkeonkim.com/wiki/java/java-atomic-integer/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-atomic-integer/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.concurrent.atomic.AtomicInteger&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;lock-free 로 원자성을 보장&lt;/strong&gt; 하는 &lt;code&gt;int&lt;/code&gt; 래퍼. 내부적으로 &lt;strong&gt;CAS (Compare-And-Swap)&lt;/strong&gt; 를 사용해 락 없이 atomic 한 read-modify-write 를 수행.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;volatile int i; i++;&lt;/code&gt; 가 thread-safe 가 아닌 이유 (read + increment + write 세 단계) 를 해결한다.&lt;/p&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;핵심-메서드&quot;&gt;핵심 메서드&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;AtomicInteger a &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AtomicInteger&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;a.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 현재 값&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;a.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                        &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 설정&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;a.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;incrementAndGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();              &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ++a, atomic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;a.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getAndIncrement&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();              &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// a++, atomic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;a.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;decrementAndGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();              &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// --a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;a.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;addAndGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// a += 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;a.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getAndAdd&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 더하기 전 값 반환&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;a.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;compareAndSet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;99&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 현재 값이 10 이면 99 로, 성공하면 true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;a.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;updateAndGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);       &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Java 8+, 람다로 갱신&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;a.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;accumulateAndGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Integer&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sum);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;cas-그-원리&quot;&gt;CAS, 그 원리&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; incrementAndGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; current &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; next &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; current &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;compareAndSet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(current, next))  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// current 와 일치하면 next 로&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; next;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // 일치하지 않으면 다른 스레드가 바꾼 것, 다시 시도&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;CPU 명령어 (&lt;code&gt;LOCK CMPXCHG&lt;/code&gt; on x86) 한 번으로 “값을 비교하고 일치하면 바꾸기” 를 atomic 하게 수행. 락 acquire/release 비용보다 훨씬 작다.&lt;/p&gt;
&lt;h2 id=&quot;volatile-vs-synchronized-vs-atomicinteger&quot;&gt;volatile vs synchronized vs AtomicInteger&lt;/h2&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;옵션&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;가시성&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;atomic read-modify-write&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;락 비용&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;int i;&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;없음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;volatile int i;&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗ (i++ 안 됨)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;없음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;synchronized&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;중간&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;AtomicInteger&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓ (CAS)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;매우 작음 (저경합)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
&lt;strong&gt;단일 변수의 atomic 갱신만 필요하면 AtomicInteger 가 거의 항상 최선.&lt;/strong&gt; 여러 변수 간 invariant 보호가 필요하면 [[ReentrantLock]] 또는 &lt;code&gt;synchronized&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;고경합에서의-문제-longadder&quot;&gt;고경합에서의 문제, LongAdder&lt;/h2&gt;
&lt;p&gt;CAS 는 저경합에서 빠르다. 하지만 &lt;strong&gt;수십 스레드가 같은 AtomicInteger 에 동시 증가&lt;/strong&gt; 하면 CAS 실패가 폭주, 성능이 락보다 떨어질 수 있다.&lt;/p&gt;
&lt;p&gt;이때 [[LongAdder]] 가 해법. 내부적으로 여러 cell 에 분산 누적 후 합산.&lt;/p&gt;
&lt;h2 id=&quot;사용-예&quot;&gt;사용 예&lt;/h2&gt;
&lt;h3 id=&quot;카운터&quot;&gt;카운터&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; RequestCounter&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AtomicInteger total &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AtomicInteger&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; onRequest&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { total.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;incrementAndGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; count&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; total.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;시퀀스-생성&quot;&gt;시퀀스 생성&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AtomicInteger seq &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AtomicInteger&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; nextId&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; seq.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;incrementAndGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;상태-전이-cas&quot;&gt;상태 전이 (CAS)&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AtomicInteger state &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AtomicInteger&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(STATE_READY);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; tryStart&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; state.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;compareAndSet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(STATE_READY, STATE_RUNNING);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;상태 머신을 락 없이 안전하게 전이.&lt;/p&gt;
&lt;h2 id=&quot;aba-문제&quot;&gt;ABA 문제&lt;/h2&gt;
&lt;p&gt;CAS 의 알려진 한계. A → B → A 로 변한 값을 “안 바뀜” 으로 잘못 판단할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 1. T1 이 값 A 를 읽음&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; v &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; a.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 2. T2 가 A → B 로 변경&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 3. T2 가 B → A 로 변경&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 4. T1 의 CAS(A, x) 성공, 하지만 이 사이에 두 번 바뀐 사실 모름&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;해법: &lt;code&gt;AtomicStampedReference&lt;/code&gt; 가 stamp (버전) 도 같이 비교.&lt;/p&gt;
&lt;h2 id=&quot;다른-atomic-타입&quot;&gt;다른 Atomic 타입&lt;/h2&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;타입&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;용도&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;AtomicInteger&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;int&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;AtomicLong&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;long&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;AtomicBoolean&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;boolean&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[[AtomicReference]]&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;임의 객체 참조&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;AtomicIntegerArray&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;int 배열의 원자 갱신&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;AtomicLongArray&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;long 배열&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;AtomicReferenceArray&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;객체 배열&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[[LongAdder]]&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;고경합 카운터&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;DoubleAdder, LongAccumulator&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;람다 누적&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[volatile]]&lt;/li&gt;
&lt;li&gt;[[ReentrantLock]]&lt;/li&gt;
&lt;li&gt;[[AtomicReference]]&lt;/li&gt;
&lt;li&gt;[[LongAdder]]&lt;/li&gt;
&lt;li&gt;[[Non-Blocking]]&lt;/li&gt;
&lt;li&gt;Brian Goetz, &lt;em&gt;Java Concurrency in Practice&lt;/em&gt;, §15 Atomic Variables and Nonblocking Synchronization&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>concurrent</category><category>atomic</category><category>cas</category><category>lock-free</category><author>koa (김신건)</author></item><item><title>[Java] AtomicReference</title><link>https://shinkeonkim.com/wiki/java/java-atomic-reference/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-atomic-reference/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.concurrent.atomic.AtomicReference&amp;#x3C;V&gt;&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;객체 참조를 atomic 하게 갱신&lt;/strong&gt; 하는 래퍼. &lt;code&gt;volatile&lt;/code&gt; 참조 + CAS 의 결합.&lt;/p&gt;
&lt;p&gt;[[AtomicInteger]] 의 객체 버전. 불변 객체 패턴, 상태 머신, lock-free 자료구조의 빌딩 블록.&lt;/p&gt;
&lt;h2 id=&quot;핵심-메서드&quot;&gt;핵심 메서드&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;AtomicReference&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; ref &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AtomicReference&amp;#x3C;&gt;(initial);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ref.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                            &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 현재 참조&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ref.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(newConfig);                   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 단순 설정 (volatile write)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ref.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;compareAndSet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(expected, newVal);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// CAS, 성공 시 true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ref.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getAndSet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(newVal);                &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 이전 값 반환 + 새 값으로&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ref.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;updateAndGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(c &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; c.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;withFoo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)); &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 람다로 갱신 (CAS 루프 내장)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ref.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;accumulateAndGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(arg, (cur, a) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ...);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;가장-흔한-패턴-불변-객체-교체&quot;&gt;가장 흔한 패턴, 불변 객체 교체&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ConfigHolder&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AtomicReference&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; ref &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AtomicReference&amp;#x3C;&gt;(defaultConfig);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Config &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ref.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; reload&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Config &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;newConfig&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        ref.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(newConfig);              &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// volatile write, 다른 스레드 즉시 봄&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; update&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Function&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;updater&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        ref.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;updateAndGet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(updater);       &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// CAS 루프, 동시 update 안전&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Config&lt;/code&gt; 가 &lt;strong&gt;불변&lt;/strong&gt; 이면 한 번 참조한 객체는 변하지 않는다. 새 설정으로 교체할 때 참조만 atomic 하게 바꾸면 안전. [[CopyOnWriteArrayList]] 의 사상.&lt;/p&gt;
&lt;h2 id=&quot;사용-사례&quot;&gt;사용 사례&lt;/h2&gt;
&lt;h3 id=&quot;1-lock-free-단일-객체-swap&quot;&gt;1. lock-free 단일 객체 swap&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AtomicReference&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Snapshot&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; snapshot &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AtomicReference&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Writer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;snapshot.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;takeSnapshot&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Reader (lock-free)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Snapshot s &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; snapshot.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;process&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(s);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-상태-머신&quot;&gt;2. 상태 머신&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;enum&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; State&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;READY&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;RUNNING&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;STOPPED&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AtomicReference&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;State&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; state &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AtomicReference&amp;#x3C;&gt;(State.READY);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; state.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;compareAndSet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(State.READY, State.RUNNING);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;3-lock-free-자료구조의-노드-포인터&quot;&gt;3. lock-free 자료구조의 노드 포인터&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; E value;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    AtomicReference&amp;#x3C;Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&gt; next;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;[[ConcurrentLinkedQueue]] 의 internal pattern.&lt;/p&gt;
&lt;h2 id=&quot;aba-문제와-해법&quot;&gt;ABA 문제와 해법&lt;/h2&gt;
&lt;p&gt;[[AtomicInteger]] 와 같은 ABA 문제. 해법.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;AtomicStampedReference&amp;#x3C;V&gt;&lt;/code&gt;&lt;/strong&gt;: stamp (int 버전) 추가&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;AtomicMarkableReference&amp;#x3C;V&gt;&lt;/code&gt;&lt;/strong&gt;: boolean mark 추가 (삭제 표시 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;AtomicStampedReference&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; ref &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AtomicStampedReference&amp;#x3C;&gt;(node, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] stampHolder &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Node current &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ref.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(stampHolder);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ref.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;compareAndSet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(current, newNode, stampHolder[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;], stampHolder[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[AtomicInteger]]&lt;/li&gt;
&lt;li&gt;[[volatile]]&lt;/li&gt;
&lt;li&gt;[[CopyOnWriteArrayList]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentLinkedQueue]]&lt;/li&gt;
&lt;li&gt;[[Non-Blocking]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>concurrent</category><category>atomic</category><category>cas</category><category>lock-free</category><category>reference</category><author>koa (김신건)</author></item><item><title>[Java] BlockingQueue</title><link>https://shinkeonkim.com/wiki/java/java-blocking-queue/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-blocking-queue/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.concurrent.BlockingQueue&amp;#x3C;E&gt;&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;요소를 가져올 때 비어 있으면 대기&lt;/strong&gt;, &lt;strong&gt;넣을 때 가득 차 있으면 대기&lt;/strong&gt; 하는 thread-safe 큐 인터페이스. 생산자-소비자 (producer-consumer) 패턴의 표준 구현체.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;take()&lt;/code&gt; 는 큐가 빌 때까지 [[Blocking]], &lt;code&gt;put()&lt;/code&gt; 은 큐가 가득 찰 때까지 blocking. 이름 그대로 &lt;strong&gt;block 의 성질을 활용&lt;/strong&gt; 한다.&lt;/p&gt;
&lt;p&gt;핵심 구현체 6 개.&lt;/p&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;구현&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;특징&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;ArrayBlockingQueue&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;고정 크기, 단일 락 (head/tail 공유)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;LinkedBlockingQueue&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;옵션 크기, &lt;strong&gt;두 락&lt;/strong&gt; (head/tail 분리, 더 높은 throughput)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;PriorityBlockingQueue&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;우선순위 (heap), unbounded&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;SynchronousQueue&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;용량 0, 직접 핸드오프&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;DelayQueue&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;원소가 지정된 delay 이후에만 꺼낼 수 있음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;LinkedTransferQueue&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;producer 가 consumer 도착을 기다릴 수 있음&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;핵심-메서드-매트릭스&quot;&gt;핵심 메서드 매트릭스&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;BlockingQueue&lt;/code&gt; 의 메서드는 &lt;strong&gt;꽉 참 / 비어 있음&lt;/strong&gt; 상황에 어떻게 반응하느냐로 4 가지 그룹으로 나뉜다.&lt;/p&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;동작&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;예외 throw&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;특수값 반환&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;block&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;timeout&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;insert&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;add(e)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;offer(e)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;put(e)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;offer(e, t, u)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;remove&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;remove()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;poll()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;take()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;poll(t, u)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;peek&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;element()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;peek()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;(없음)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;(없음)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3 id=&quot;예외-throw&quot;&gt;예외 throw&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(elem);        &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 큐 가득 → IllegalStateException&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();         &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 큐 비어 있음 → NoSuchElementException&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;특수값-반환&quot;&gt;특수값 반환&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ok &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;offer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(elem);   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 가득 → false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Task t &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;poll&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();             &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 비어 있음 → null&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;block-blockingqueue-의-핵심&quot;&gt;Block (BlockingQueue 의 핵심)&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(elem);        &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 가득 → 자리 날 때까지 block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Task t &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;take&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 비어 있음 → 원소 들어올 때까지 block&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;timeout&quot;&gt;Timeout&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ok &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;offer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(elem, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, TimeUnit.MILLISECONDS);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Task t &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;poll&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;500&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, TimeUnit.MILLISECONDS);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;[!TIP]
어떤 그룹을 쓸지가 설계 결정이다. &lt;strong&gt;반드시 처리해야 함 → put/take&lt;/strong&gt;, &lt;strong&gt;포기 가능 → offer/poll&lt;/strong&gt;, &lt;strong&gt;포기 + 타임아웃 → timed offer/poll&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;가장-흔한-패턴-producer-consumer&quot;&gt;가장 흔한 패턴, Producer-Consumer&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; BlockingQueue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; queue &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; LinkedBlockingQueue&amp;#x3C;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Producer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Thread&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        Task t &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; generate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(t);              &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 큐가 가득 차면 자연스럽게 backpressure&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Consumer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Thread&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        Task t &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;take&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();     &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 원소 올 때까지 block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        process&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(t);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 코드의 강점.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;명시적 동기화 코드가 없다&lt;/strong&gt;, BlockingQueue 가 모두 처리&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;자연스러운 backpressure&lt;/strong&gt;, producer 가 너무 빠르면 큐가 가득 차서 자동으로 throttle&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;확장 가능&lt;/strong&gt;, producer 또는 consumer 를 N 개로 늘려도 코드 변경 없음&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;구현체별-비교&quot;&gt;구현체별 비교&lt;/h2&gt;
&lt;h3 id=&quot;arrayblockingqueue&quot;&gt;ArrayBlockingQueue&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;내부: 원형 배열 (circular buffer)&lt;/li&gt;
&lt;li&gt;락: &lt;strong&gt;단일 ReentrantLock&lt;/strong&gt;, head 와 tail 모두 같은 락 보호&lt;/li&gt;
&lt;li&gt;크기: &lt;strong&gt;고정&lt;/strong&gt; (생성 시 지정)&lt;/li&gt;
&lt;li&gt;공정성: 옵션 (FIFO 보장)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;BlockingQueue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; q &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayBlockingQueue&amp;#x3C;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;BlockingQueue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; fair &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayBlockingQueue&amp;#x3C;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;장점: 메모리 미리 할당, GC 압력 작음.
단점: 락 경합 (read/write 가 같은 락).&lt;/p&gt;
&lt;h3 id=&quot;linkedblockingqueue&quot;&gt;LinkedBlockingQueue&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;내부: linked list (head, tail 포인터)&lt;/li&gt;
&lt;li&gt;락: &lt;strong&gt;두 개의 ReentrantLock&lt;/strong&gt; (&lt;code&gt;takeLock&lt;/code&gt;, &lt;code&gt;putLock&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;크기: optionally bounded (&lt;code&gt;Integer.MAX_VALUE&lt;/code&gt; 기본)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;BlockingQueue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; q &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; LinkedBlockingQueue&amp;#x3C;&gt;();       &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// unbounded&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;BlockingQueue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; q2 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; LinkedBlockingQueue&amp;#x3C;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// bounded&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;장점: producer 와 consumer 가 다른 락 → &lt;strong&gt;동시에 가능&lt;/strong&gt;.
단점: 각 원소가 노드 객체 → GC 압력.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
&lt;strong&gt;거의 모든 실무 case 의 첫 선택은 &lt;code&gt;LinkedBlockingQueue&lt;/code&gt; 또는 &lt;code&gt;ArrayBlockingQueue&lt;/code&gt;&lt;/strong&gt;. 두 락 분리 덕에 LinkedBlockingQueue 가 throughput 우위인 경우가 많다. &lt;strong&gt;크기를 반드시 bounded 로 지정&lt;/strong&gt; 하라, unbounded 는 OOM 의 원인.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;priorityblockingqueue&quot;&gt;PriorityBlockingQueue&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;내부: 힙 (heap)&lt;/li&gt;
&lt;li&gt;락: 단일 ReentrantLock&lt;/li&gt;
&lt;li&gt;크기: &lt;strong&gt;unbounded&lt;/strong&gt; (capacity 부족 시 grow)&lt;/li&gt;
&lt;li&gt;순서: &lt;code&gt;Comparator&lt;/code&gt; 또는 &lt;code&gt;Comparable&lt;/code&gt; 기준 우선순위&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;BlockingQueue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; q &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; PriorityBlockingQueue&amp;#x3C;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    100&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Comparator.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;comparingInt&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Task&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;priority).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;reversed&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;긴급 작업 우선 처리, 스케줄러 패턴에 적합.&lt;/p&gt;
&lt;h3 id=&quot;synchronousqueue&quot;&gt;SynchronousQueue&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;용량 0, &lt;strong&gt;저장 공간 없음&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;put&lt;/code&gt; 은 매칭되는 &lt;code&gt;take&lt;/code&gt; 가 있어야 진행, 반대도 마찬가지&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;직접 핸드오프 (direct handoff)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;BlockingQueue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; q &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; SynchronousQueue&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Producer: put 하면 consumer 가 take 할 때까지 block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Consumer: take 하면 producer 가 put 할 때까지 block&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;쓰임: &lt;code&gt;Executors.newCachedThreadPool()&lt;/code&gt; 의 내부 큐. 새 작업이 오면 즉시 스레드에 전달, 없으면 새 스레드 생성.&lt;/p&gt;
&lt;h3 id=&quot;delayqueue&quot;&gt;DelayQueue&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;원소는 &lt;code&gt;Delayed&lt;/code&gt; 인터페이스 구현 필요&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;delay 가 만료된 원소만&lt;/strong&gt; poll/take 로 꺼낼 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; DelayedTask&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Delayed&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; readyAt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; long&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getDelay&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(TimeUnit &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;u&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; u.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;convert&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(readyAt &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; System.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), TimeUnit.MILLISECONDS);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; compareTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Delayed &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;o&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { ... }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;BlockingQueue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;DelayedTask&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; q &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; DelayQueue&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;q.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; DelayedTask&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(System.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 5000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 5초 뒤 ready&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;q.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;take&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 5초간 block 후 반환&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;스케줄러, retry 큐, TTL 캐시 만료 처리 등.&lt;/p&gt;
&lt;h3 id=&quot;linkedtransferqueue&quot;&gt;LinkedTransferQueue&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;LinkedBlockingQueue 의 확장&lt;/li&gt;
&lt;li&gt;추가 메서드: &lt;code&gt;transfer(e)&lt;/code&gt; (consumer 가 받을 때까지 block), &lt;code&gt;tryTransfer(e)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;producer 가 consumer 의 도착을 알 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;대량 동시성에 최적화. 일반 BlockingQueue 보다 throughput 우위지만 구현 복잡.&lt;/p&gt;
&lt;h2 id=&quot;executorservice-와의-연동&quot;&gt;ExecutorService 와의 연동&lt;/h2&gt;
&lt;p&gt;Java 의 &lt;code&gt;ThreadPoolExecutor&lt;/code&gt; 가 내부적으로 &lt;code&gt;BlockingQueue&lt;/code&gt; 를 사용한다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ExecutorService pool &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ThreadPoolExecutor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;    4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;16&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;60L&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, TimeUnit.SECONDS,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; LinkedBlockingQueue&amp;#x3C;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 작업 대기열&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Executors&lt;/code&gt; factory 별 기본 큐.&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;Factory&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;내부 큐&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;newFixedThreadPool(n)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;LinkedBlockingQueue&lt;/code&gt; (unbounded ⚠️)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;newSingleThreadExecutor()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;LinkedBlockingQueue&lt;/code&gt; (unbounded ⚠️)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;newCachedThreadPool()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;SynchronousQueue&lt;/code&gt; (핸드오프)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;newScheduledThreadPool(n)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;DelayedWorkQueue&lt;/code&gt; (DelayQueue 변형)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!CAUTION]
&lt;code&gt;newFixedThreadPool&lt;/code&gt; 의 unbounded 큐가 OOM 의 단골 원인. 명시적으로 &lt;code&gt;new ThreadPoolExecutor(..., new LinkedBlockingQueue&amp;#x3C;&gt;(N))&lt;/code&gt; 로 제한해야 한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;함정&quot;&gt;함정&lt;/h2&gt;
&lt;h3 id=&quot;1-take-의-인터럽트&quot;&gt;1. &lt;code&gt;take()&lt;/code&gt; 의 인터럽트&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Task t &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;take&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (InterruptedException &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Thread.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;currentThread&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;interrupt&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 인터럽트 상태 복원&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;take()&lt;/code&gt; 는 block 중 인터럽트되면 &lt;code&gt;InterruptedException&lt;/code&gt;. 처리 안 하면 컴파일 오류. &lt;strong&gt;무시하지 말고 인터럽트 상태를 복원&lt;/strong&gt;, 그러지 않으면 상위 코드가 인터럽트를 못 본다.&lt;/p&gt;
&lt;h3 id=&quot;2-unbounded-큐의-oom-위험&quot;&gt;2. unbounded 큐의 OOM 위험&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;new LinkedBlockingQueue&amp;#x3C;&gt;()&lt;/code&gt; (인자 없이) 는 &lt;code&gt;Integer.MAX_VALUE&lt;/code&gt; 크기. producer 가 빠르면 OOM. 항상 bounded.&lt;/p&gt;
&lt;h3 id=&quot;3-drainto-사용&quot;&gt;3. drainTo 사용&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; batch &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;drainTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(batch, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 한 번에 최대 100 개를 batch 로&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;take()&lt;/code&gt; 를 반복 호출하는 것보다 훨씬 빠르다 (락 한 번에 여러 원소 이동). 배치 처리에 유용.&lt;/p&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[Object]]&lt;/li&gt;
&lt;li&gt;[[Iterable]]&lt;/li&gt;
&lt;li&gt;[[Collection]]&lt;/li&gt;
&lt;li&gt;[[Blocking]]&lt;/li&gt;
&lt;li&gt;[[Non-Blocking]]&lt;/li&gt;
&lt;li&gt;[[Synchronous]]&lt;/li&gt;
&lt;li&gt;[[Asynchronous]]&lt;/li&gt;
&lt;li&gt;[[ReentrantLock]]&lt;/li&gt;
&lt;li&gt;Brian Goetz, &lt;em&gt;Java Concurrency in Practice&lt;/em&gt;, §5.3 Blocking Queues and the Producer-Consumer Pattern&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>concurrent</category><category>queue</category><category>blocking</category><category>producer-consumer</category><category>jsr-166</category><author>koa (김신건)</author></item><item><title>[Java] Collection</title><link>https://shinkeonkim.com/wiki/java/java-collection/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-collection/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.Collection&amp;#x3C;E&gt;&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;그룹으로 묶인 객체들을 표현하는 최상위 인터페이스&lt;/strong&gt;. JCF (Java Collections Framework) 의 입구이자, [[List]] / &lt;code&gt;Set&lt;/code&gt; / &lt;code&gt;Queue&lt;/code&gt; / &lt;code&gt;Deque&lt;/code&gt; 모두 이를 확장한다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Collection&lt;/code&gt; 자체는 직접 인스턴스화하지 않는다. &lt;strong&gt;하위 인터페이스의 구현체&lt;/strong&gt; ([[ArrayList]], &lt;code&gt;HashSet&lt;/code&gt;, &lt;code&gt;LinkedList&lt;/code&gt; 등) 만이 실제 객체가 된다.&lt;/p&gt;
&lt;p&gt;상속 관계:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Iterable&amp;#x3C;E&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  └─ Collection&amp;#x3C;E&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       ├─ List&amp;#x3C;E&gt;     → ArrayList, LinkedList, Vector, CopyOnWriteArrayList&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       ├─ Set&amp;#x3C;E&gt;      → HashSet, LinkedHashSet, TreeSet, CopyOnWriteArraySet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       ├─ Queue&amp;#x3C;E&gt;    → PriorityQueue, ArrayDeque, ConcurrentLinkedQueue&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       │   └─ Deque&amp;#x3C;E&gt; → ArrayDeque, LinkedList, ConcurrentLinkedDeque&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;       └─ (Map 은 Collection 이 아니다, 별도 계층)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
&lt;strong&gt;&lt;code&gt;Map&lt;/code&gt; 은 &lt;code&gt;Collection&lt;/code&gt; 의 자식이 아니다.&lt;/strong&gt; key-value pair 의 모음이라 일반적인 element 모음과 의미가 달라 별도 계층. &lt;code&gt;Map.entrySet()&lt;/code&gt; / &lt;code&gt;Map.keySet()&lt;/code&gt; / &lt;code&gt;Map.values()&lt;/code&gt; 가 &lt;code&gt;Set&lt;/code&gt;/&lt;code&gt;Collection&lt;/code&gt; 을 반환해 다리를 놓는다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;핵심-메서드-그룹&quot;&gt;핵심 메서드 그룹&lt;/h2&gt;
&lt;h3 id=&quot;추가삭제&quot;&gt;추가/삭제&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;add(E e)&lt;/code&gt;: 원소 추가, 추가 됐으면 true (Set 이 이미 갖고 있으면 false)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;remove(Object o)&lt;/code&gt;: 첫 매칭 원소 제거&lt;/li&gt;
&lt;li&gt;&lt;code&gt;addAll(Collection)&lt;/code&gt;, &lt;code&gt;removeAll(Collection)&lt;/code&gt;, &lt;code&gt;retainAll(Collection)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;clear()&lt;/code&gt;: 모두 삭제&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;조회&quot;&gt;조회&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;contains(Object o)&lt;/code&gt;: 포함 여부&lt;/li&gt;
&lt;li&gt;&lt;code&gt;containsAll(Collection)&lt;/code&gt;: 모두 포함하는지&lt;/li&gt;
&lt;li&gt;&lt;code&gt;size()&lt;/code&gt;, &lt;code&gt;isEmpty()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iterator()&lt;/code&gt;: 순회용 ([[Iterable]] 에서 상속)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stream()&lt;/code&gt;, &lt;code&gt;parallelStream()&lt;/code&gt;: Java 8+ Stream API 입구&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;배열-변환&quot;&gt;배열 변환&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;toArray()&lt;/code&gt;: &lt;code&gt;Object[]&lt;/code&gt; 반환&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toArray(T[] a)&lt;/code&gt;: 지정 타입 배열 반환&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toArray(IntFunction&amp;#x3C;T[]&gt; generator)&lt;/code&gt;: Java 11+, 더 명확&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Collection&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; c &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; List.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Object&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] arr1 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; c.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;toArray&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Object[]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] arr2 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; c.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;toArray&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;]);    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// String[] (관행: 빈 배열 전달)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] arr3 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; c.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;toArray&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[]&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// String[] (Java 11+ 권장)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;collection-의-약속과-한계&quot;&gt;Collection 의 약속과 한계&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Collection&lt;/code&gt; 인터페이스 자체는 &lt;strong&gt;순서, 중복 허용, 동기화&lt;/strong&gt; 에 대한 약속이 없다.&lt;/p&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;특성&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;Collection&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;List&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;Set&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;Queue&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;순서 보장&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓ (인덱스)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;구현 의존&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓ (FIFO 등)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;중복 허용&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;구현 의존&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;get(int)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;따라서 코드에서 변수 타입을 &lt;code&gt;Collection&amp;#x3C;E&gt;&lt;/code&gt; 로 받으면 &lt;strong&gt;인덱스 접근, 정렬, 중복 검사 같은 가정을 못 한다&lt;/strong&gt;. 함수 매개변수에서 일부러 약한 약속만 쓸 때 유용.&lt;/p&gt;
&lt;h2 id=&quot;자주-쓰이는-구현-한눈에&quot;&gt;자주 쓰이는 구현 한눈에&lt;/h2&gt;




























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;구현&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;하위 인터페이스&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;특징&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[[ArrayList]]&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;List&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;가장 흔한 기본&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[[LinkedList]]&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;List, Deque&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;양방향 연결 리스트&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[[Vector]]&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;List&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;레거시 synchronized&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[[CopyOnWriteArrayList]]&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;List&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;읽기 多, 쓰기 少&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;HashSet&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Set&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;해시 기반, 순서 없음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;LinkedHashSet&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Set&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;삽입 순서 유지&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;TreeSet&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Set&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;정렬 (Comparable / Comparator)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;PriorityQueue&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Queue&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;힙 기반&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;ArrayDeque&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Queue, Deque&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;배열 기반 deque (스택보다 빠름)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;ConcurrentLinkedQueue&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;Queue&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;동시성 lock-free&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;map-은-별도-계층&quot;&gt;Map 은 별도 계층&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Map&amp;#x3C;K,V&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ├─ HashMap, LinkedHashMap, TreeMap&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ├─ Hashtable (legacy)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  ├─ ConcurrentHashMap&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  └─ EnumMap, IdentityHashMap, WeakHashMap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Map&lt;/code&gt; 은 &lt;code&gt;Collection&lt;/code&gt; 을 extends 하지 않는다. 다만 다음 메서드로 view 를 제공.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Map&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; map &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ...;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Set&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; keys &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;keySet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();              &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// key 만 Set&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Collection&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; values &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;values&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// value 모음&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Set&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Entry&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&gt; entries &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;entrySet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 쌍&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 view 들을 통해 &lt;code&gt;Collection&lt;/code&gt; 인터페이스와 호환된다.&lt;/p&gt;
&lt;h2 id=&quot;컬렉션-view-와-변경-전파&quot;&gt;컬렉션 view 와 변경 전파&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Map.keySet()&lt;/code&gt;, &lt;code&gt;subList()&lt;/code&gt;, &lt;code&gt;Arrays.asList()&lt;/code&gt; 등은 &lt;strong&gt;view&lt;/strong&gt; 를 반환. view 에 대한 변경이 원본에 전파된다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Map&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; map &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; HashMap&amp;#x3C;&gt;(Map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Set&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; keys &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;keySet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;keys.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ← map 에서도 &quot;a&quot; 삭제&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; view &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;subList&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;view.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;99&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                 &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ← list[1] = 99&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;[!CAUTION]
view 의 추가/삭제는 원본에 영향을 준다. 독립 사본이 필요하면 &lt;code&gt;new ArrayList&amp;#x3C;&gt;(view)&lt;/code&gt;, &lt;code&gt;new HashSet&amp;#x3C;&gt;(keys)&lt;/code&gt; 등으로 명시적 복사.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;불변-컬렉션-java-9&quot;&gt;불변 컬렉션 (Java 9+)&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;List.of()&lt;/code&gt;, &lt;code&gt;Set.of()&lt;/code&gt;, &lt;code&gt;Map.of()&lt;/code&gt; 가 추가됐다. 반환되는 컬렉션은:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;immutable&lt;/strong&gt;: add/remove/clear 호출 시 &lt;code&gt;UnsupportedOperationException&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;null 거부&lt;/strong&gt;: null 원소를 넣으면 &lt;code&gt;NullPointerException&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;구조 공유 없음&lt;/strong&gt;: 안전한 공유 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; primes &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; List.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;7&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Set&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; langs &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Set.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Java&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Kotlin&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Scala&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Map&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; ages &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Alice&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;30&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;Bob&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;25&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;기존 &lt;code&gt;Collections.unmodifiableList(...)&lt;/code&gt; 보다 권장.&lt;/p&gt;
&lt;h2 id=&quot;동기화-synchronized-래퍼&quot;&gt;동기화 (synchronized) 래퍼&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Collections.synchronizedXxx(...)&lt;/code&gt; 가 모든 메서드를 &lt;code&gt;synchronized&lt;/code&gt; 로 감싼 래퍼를 반환.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; safe &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Collections.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;synchronizedList&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Map&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; safeMap &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Collections.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;synchronizedMap&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; HashMap&amp;#x3C;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Set&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; safeSet &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Collections.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;synchronizedSet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; HashSet&amp;#x3C;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;[[Vector]] 와 비슷한 메서드별 락 패턴. 복합 연산은 외부 동기화 필요.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;synchronized&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (safe) {            &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ← 외부 동기화 필수&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (Integer x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; safe) {     &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 순회도 락 안에서&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;진짜 동시성에는 [[CopyOnWriteArrayList]], [[ConcurrentHashMap]] 등 동시성 컬렉션 권장.&lt;/p&gt;
&lt;h2 id=&quot;collection-의-함정-정리&quot;&gt;Collection 의 함정 정리&lt;/h2&gt;
&lt;h3 id=&quot;1-collectionremoveallc-비용&quot;&gt;1. &lt;code&gt;Collection.removeAll(c)&lt;/code&gt; 비용&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;removeAll&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(otherList);   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// O(n × m), otherList 가 List 면 contains 가 O(m)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;removeAll&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(otherSet);    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// O(n), Set 의 contains 가 O(1)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;removeAll&lt;/code&gt; 의 매개변수는 contains() 가 빠른 컬렉션을 넘기는 게 좋다.&lt;/p&gt;
&lt;h3 id=&quot;2-collectionequals-는-listset-별로-다르다&quot;&gt;2. &lt;code&gt;Collection.equals&lt;/code&gt; 는 List/Set 별로 다르다&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; a &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; List.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Set&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; b &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Set.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;a.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;equals&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(b);   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// false! List.equals 와 Set.equals 의 의미가 다름&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Collection&lt;/code&gt; 자체는 &lt;code&gt;equals&lt;/code&gt; 의미를 명세하지 않음. 하위 인터페이스가 정의.&lt;/p&gt;
&lt;h3 id=&quot;3-raw-type-금지&quot;&gt;3. raw type 금지&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ Java 5 이전 스타일&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Collection c &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ArrayList&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;c.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;c.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;42&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);     &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 컴파일은 됨, 런타임에 ClassCastException&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ✓ generic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Collection&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; c &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[Object]]&lt;/li&gt;
&lt;li&gt;[[Iterable]]&lt;/li&gt;
&lt;li&gt;[[List]]&lt;/li&gt;
&lt;li&gt;[[ArrayList]]&lt;/li&gt;
&lt;li&gt;[[LinkedList]]&lt;/li&gt;
&lt;li&gt;[[Vector]]&lt;/li&gt;
&lt;li&gt;[[CopyOnWriteArrayList]]&lt;/li&gt;
&lt;li&gt;[[fail-fast iterator]]&lt;/li&gt;
&lt;li&gt;Joshua Bloch, &lt;em&gt;Effective Java&lt;/em&gt; (3rd ed.), Items 28-31 (배열보다 리스트, 한정적 와일드카드 등)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>collection</category><category>fundamentals</category><category>interface</category><category>jcf</category><author>koa (김신건)</author></item><item><title>[Java] ConcurrentHashMap</title><link>https://shinkeonkim.com/wiki/java/java-concurrent-hashmap/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-concurrent-hashmap/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.concurrent.ConcurrentHashMap&amp;#x3C;K,V&gt;&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;고동시성 환경에서 사용 가능한 &lt;code&gt;Map&lt;/code&gt;&lt;/strong&gt; 구현. JSR-166 (Java 5) 도입, Java 8 에서 내부 구조가 크게 재작성됐다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;HashMap&lt;/code&gt; 과 같은 인터페이스를 제공하면서 thread-safe. &lt;code&gt;Hashtable&lt;/code&gt; (legacy) 보다 압도적으로 빠르고, &lt;code&gt;Collections.synchronizedMap(...)&lt;/code&gt; 보다 훨씬 좋은 동시성을 제공한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;실무에서 thread-safe Map 이 필요할 때 거의 항상 첫 번째 선택.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;내부-구조-java-8&quot;&gt;내부 구조 (Java 8+)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ConcurrentHashMap&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AbstractMap&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ConcurrentMap&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Serializable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    transient&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; volatile&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;[] table;       &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 버킷 배열&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; transient&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; volatile&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;[] nextTable;  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// resize 중 임시 테이블&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; transient&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; volatile&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; baseCount;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; transient&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; volatile&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sizeCtl;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Map.Entry&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; K key;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        volatile&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; V val;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        volatile&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; next;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;table&lt;/code&gt;&lt;/strong&gt;: 버킷 (bin) 배열. 각 버킷은 &lt;code&gt;Node&lt;/code&gt; 의 linked list 또는 (TREEIFY 임계 이상이면) red-black tree.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;volatile&lt;/code&gt;&lt;/strong&gt;: 모든 핵심 필드가 volatile, 락 없이 일관된 view.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CAS&lt;/strong&gt;: 새 노드 삽입은 &lt;code&gt;Unsafe.compareAndSwapObject&lt;/code&gt; 로 atomic.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;synchronized (Node)&lt;/strong&gt;: 같은 버킷에 충돌이 생기면 그 &lt;strong&gt;버킷의 첫 노드&lt;/strong&gt; 에 synchronized.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Java 7 까지는 &lt;strong&gt;segment-based&lt;/strong&gt; 였다 (16개 segment 로 분할 동기화). Java 8 부터는 &lt;strong&gt;bin-level (버킷 단위) 동기화&lt;/strong&gt; 로 진화. 충돌 단위가 더 작아져 동시성이 크게 향상.&lt;/p&gt;
&lt;h2 id=&quot;핵심-알고리즘&quot;&gt;핵심 알고리즘&lt;/h2&gt;
&lt;h3 id=&quot;get-락-없이&quot;&gt;get, 락 없이&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; V &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Object key) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; h &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; spread&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(key.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;hashCode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;[] tab &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; table;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; n &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; tab.length;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; e &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; tabAt&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(tab, (n &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; h);   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// volatile read&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (e &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (e.hash &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; h &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; key.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;equals&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(e.key)) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; e.val;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        e &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; e.next;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;읽기에는 &lt;strong&gt;락이 없다.&lt;/strong&gt; 모든 필드가 volatile 이라 다른 스레드의 쓰기가 즉시 보인다. 사실상 &lt;code&gt;HashMap.get()&lt;/code&gt; 만큼 빠르다.&lt;/p&gt;
&lt;h3 id=&quot;put-빈-버킷이면-cas-충돌이면-synchronized&quot;&gt;put, 빈 버킷이면 CAS, 충돌이면 synchronized&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; V &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;putVal&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(K key, V value, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;boolean&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; onlyIfAbsent) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; h &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; spread&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(key.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;hashCode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;[] tab &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; table;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (tab.length &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; h;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; f &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; tabAt&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(tab, i);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (f &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // 빈 버킷, CAS 로 새 노드 삽입 (lock-free)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;casTabAt&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(tab, i, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Node&amp;#x3C;&gt;(h, key, value, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                break&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // 충돌, 첫 노드에 synchronized&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            synchronized&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (f) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;tabAt&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(tab, i) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; f) {     &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// double-check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;                    // 같은 버킷에 추가 또는 갱신&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            break&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;핵심 통찰:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;충돌이 없으면 락도 없다&lt;/strong&gt;. CAS 한 번으로 끝.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;충돌이 있으면 그 버킷에만 락&lt;/strong&gt;. 다른 버킷은 영향 없음.&lt;/li&gt;
&lt;li&gt;락의 단위가 &lt;strong&gt;버킷 1 개&lt;/strong&gt; (보통 노드 0-2 개).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;동시성-특성&quot;&gt;동시성 특성&lt;/h2&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;작업&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;동시성&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;다른 키의 &lt;code&gt;get&lt;/code&gt; / &lt;code&gt;put&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;완전 병렬&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;같은 버킷의 &lt;code&gt;put&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;직렬 (synchronized)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;get&lt;/code&gt; 과 &lt;code&gt;put&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;get&lt;/code&gt; 은 락 없음, 진행 가능&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;resize&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;다른 스레드도 도와줌 (cooperative)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;즉, 같은 키에 동시 &lt;code&gt;put&lt;/code&gt; 하지 않는 한 거의 모두 병렬.&lt;/p&gt;
&lt;h2 id=&quot;iterator-는-weakly-consistent&quot;&gt;Iterator 는 weakly consistent&lt;/h2&gt;
&lt;p&gt;[[fail-fast iterator]] 가 아니다. 순회 중 다른 스레드가 수정해도 &lt;code&gt;ConcurrentModificationException&lt;/code&gt; 을 던지지 않는다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Map&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; map &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ConcurrentHashMap&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;); map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Iterator&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Entry&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&gt; it &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;entrySet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;c&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 순회 중 추가&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (it.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;hasNext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(it.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// CME 안 던짐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;대신 &lt;strong&gt;weakly consistent&lt;/strong&gt;, 순회 시작 후 변경된 내용이 보일 수도 있고 안 보일 수도 있다. 일관된 snapshot 이 아니다.&lt;/p&gt;
&lt;h2 id=&quot;원자-연산-메서드들&quot;&gt;원자 연산 메서드들&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ConcurrentHashMap&lt;/code&gt; 은 단순 &lt;code&gt;put&lt;/code&gt; / &lt;code&gt;get&lt;/code&gt; 외에도 &lt;strong&gt;원자성을 보장하는 복합 연산&lt;/strong&gt; 을 제공한다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 키가 없으면 추가, 있으면 기존 값 반환&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;putIfAbsent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 키가 있으면 람다 적용해 값 갱신, 없으면 추가&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;compute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, (k, v) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; v &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; v &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 키가 없을 때만 람다 호출해 추가&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;computeIfAbsent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, k &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; expensiveCompute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(k));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 키가 있을 때만 람다 호출해 갱신&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;computeIfPresent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, (k, v) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; v &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 추가 또는 람다로 병합&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;merge&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Integer&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sum);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 메서드들은 &lt;strong&gt;버킷 단위 락 안에서 람다를 실행&lt;/strong&gt; 한다. 람다 안에서 다시 같은 map 을 수정하면 deadlock 가능, 주의.&lt;/p&gt;
&lt;h2 id=&quot;java-8-의-추가-기능&quot;&gt;Java 8 의 추가 기능&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 병렬 처리 (forEach, search, reduce)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, (k, v) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; process&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(k, v));   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 1 = 병렬 threshold&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;search&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, (k, v) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; v &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ?&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; k &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; sum &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;reduceValues&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0L&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Long&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sum);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;지정한 threshold (병렬 진입 한계) 보다 entry 가 많으면 ForkJoinPool 로 병렬 실행. 큰 map 의 일괄 처리에 유리.&lt;/p&gt;
&lt;h2 id=&quot;size-의-약점&quot;&gt;size 의 약점&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ConcurrentHashMap.size()&lt;/code&gt; 는 &lt;strong&gt;정확한 값이 아닐 수 있다.&lt;/strong&gt; Java 8 부터는 &lt;code&gt;LongAdder&lt;/code&gt; 기반으로 분산 카운터를 사용하므로 빠르지만 여전히 동시 수정 중에는 부정확.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 호출 시점의 추정&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 다른 스레드가 그 사이 추가/삭제하면 실제와 다를 수 있음&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;정확한 카운트가 필요한 시나리오라면 외부 카운터를 따로 유지하거나, snapshot 을 위해 외부 동기화.&lt;/p&gt;
&lt;h2 id=&quot;null-비허용&quot;&gt;null 비허용&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;HashMap&lt;/code&gt; 과 달리 &lt;strong&gt;key 도 value 도 null 불가&lt;/strong&gt;. null 을 넣으면 &lt;code&gt;NullPointerException&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Map&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; chm &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ConcurrentHashMap&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;chm.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ NPE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;chm.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ NPE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;chm.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);       &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ NPE&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이유: &lt;code&gt;get(null)&lt;/code&gt; 이 반환한 null 이 &lt;strong&gt;“키가 없음”&lt;/strong&gt; 인지 &lt;strong&gt;“키는 있는데 값이 null”&lt;/strong&gt; 인지 동시성 안에서 구분 불가능. 처음부터 허용하지 않는 게 안전.&lt;/p&gt;
&lt;h2 id=&quot;hashmap--hashtable--synchronizedmap-비교&quot;&gt;HashMap / Hashtable / synchronizedMap 비교&lt;/h2&gt;





























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;항목&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;HashMap&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;Hashtable&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;synchronizedMap&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;ConcurrentHashMap&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Thread-safe&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓ (메서드별 lock)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓ (메서드별 lock)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓ (bin-level)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;null key/value&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;1 / 다수&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;1 / 다수&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;도입&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;JDK 1.2&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;JDK 1.0&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;JDK 1.2&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;JDK 1.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;동시 read 처리량&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;n/a&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;직렬화&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;직렬화&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;병렬&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;동시 write 처리량&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;n/a&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;직렬화&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;직렬화&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;버킷별 직렬, 다른 버킷 병렬&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Iterator&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;fail-fast&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;fail-fast&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;fail-fast&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;weakly consistent&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;권장&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;단일 스레드&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗ legacy&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;가벼운 보호&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;동시성 표준&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;실무-사용-예&quot;&gt;실무 사용 예&lt;/h2&gt;
&lt;h3 id=&quot;1-캐시&quot;&gt;1. 캐시&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Map&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;User&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; cache &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ConcurrentHashMap&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; User &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getUser&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(String id) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cache.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;computeIfAbsent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(id, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;loadFromDb);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;computeIfAbsent&lt;/code&gt; 가 원자성을 보장하므로 같은 id 로 동시 호출 시 한 번만 &lt;code&gt;loadFromDb&lt;/code&gt; 실행.&lt;/p&gt;
&lt;h3 id=&quot;2-카운터&quot;&gt;2. 카운터&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Map&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;LongAdder&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; counts &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ConcurrentHashMap&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; increment&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(String key) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    counts.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;computeIfAbsent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(key, k &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LongAdder&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;increment&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;LongAdder&lt;/code&gt; 가 고경합에 강함. &lt;code&gt;AtomicLong&lt;/code&gt; 보다 빠를 때가 많다.&lt;/p&gt;
&lt;h3 id=&quot;3-spring-의-빈-레지스트리&quot;&gt;3. Spring 의 빈 레지스트리&lt;/h3&gt;
&lt;p&gt;Spring 내부에 ConcurrentHashMap 이 많이 쓰인다 (&lt;code&gt;DefaultListableBeanFactory.singletonObjects&lt;/code&gt; 등). 캐시류는 거의 모두 이 자료구조.&lt;/p&gt;
&lt;h2 id=&quot;함정&quot;&gt;함정&lt;/h2&gt;
&lt;h3 id=&quot;1-compute-안의-부수효과&quot;&gt;1. compute 안의 부수효과&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;compute&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, (k, v) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;other&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;99&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ 같은 버킷이면 deadlock, 다른 버킷이면 UB&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; v &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;람다 안에서 같은 map 수정 금지.&lt;/p&gt;
&lt;h3 id=&quot;2-size--put-두-번-호출&quot;&gt;2. size + put 두 번 호출&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {       &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ← race&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(key, value);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 사이에 다른 스레드가 추가했을 수 있다. &lt;code&gt;compute&lt;/code&gt;, &lt;code&gt;merge&lt;/code&gt; 같은 원자 메서드로 표현 가능한지 먼저 검토.&lt;/p&gt;
&lt;h3 id=&quot;3-iterator-의-snapshot-가정&quot;&gt;3. iterator 의 snapshot 가정&lt;/h3&gt;
&lt;p&gt;weakly consistent 라서 일관된 view 가 아니다. 정합성 있는 read 가 필요하면 별도 동기화 또는 &lt;code&gt;CopyOnWriteArrayList&lt;/code&gt; 같은 snapshot 컬렉션.&lt;/p&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[Object]]&lt;/li&gt;
&lt;li&gt;[[Iterable]]&lt;/li&gt;
&lt;li&gt;[[Collection]]&lt;/li&gt;
&lt;li&gt;[[CopyOnWriteArrayList]]&lt;/li&gt;
&lt;li&gt;[[Vector]]&lt;/li&gt;
&lt;li&gt;[[fail-fast iterator]]&lt;/li&gt;
&lt;li&gt;[[volatile]]&lt;/li&gt;
&lt;li&gt;[[ReentrantLock]]&lt;/li&gt;
&lt;li&gt;[[Non-Blocking]]&lt;/li&gt;
&lt;li&gt;Brian Goetz, &lt;em&gt;Java Concurrency in Practice&lt;/em&gt;, §5.2 Concurrent Collections&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>collection</category><category>map</category><category>concurrent</category><category>jsr-166</category><category>hash</category><category>thread-safe</category><author>koa (김신건)</author></item><item><title>[Java] ConcurrentLinkedDeque</title><link>https://shinkeonkim.com/wiki/java/java-concurrentlinkeddeque/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-concurrentlinkeddeque/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.concurrent.ConcurrentLinkedDeque&amp;#x3C;E&gt;&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;lock-free&lt;/strong&gt; [[Deque]]. [[ConcurrentLinkedQueue]] 의 양방향 버전. JDK 1.7 추가.&lt;/p&gt;
&lt;p&gt;양 끝 모두에서 add/remove 가능, 모든 연산이 CAS 기반.&lt;/p&gt;
&lt;h2 id=&quot;내부-구조&quot;&gt;내부 구조&lt;/h2&gt;
&lt;p&gt;이중 연결 리스트 (&lt;code&gt;prev&lt;/code&gt;, &lt;code&gt;next&lt;/code&gt; 모두 volatile) 를 lock-free 알고리즘으로 관리. ConcurrentLinkedQueue 의 단방향보다 복잡하다.&lt;/p&gt;
&lt;h2 id=&quot;복잡도&quot;&gt;복잡도&lt;/h2&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;작업&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;시간&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;동시성&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;addFirst&lt;/code&gt;, &lt;code&gt;addLast&lt;/code&gt;, &lt;code&gt;offerFirst&lt;/code&gt;, &lt;code&gt;offerLast&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;amortized O(1)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;lock-free&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;pollFirst&lt;/code&gt;, &lt;code&gt;pollLast&lt;/code&gt;, &lt;code&gt;removeFirst&lt;/code&gt;, &lt;code&gt;removeLast&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;amortized O(1)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;lock-free&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;peekFirst&lt;/code&gt;, &lt;code&gt;peekLast&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;volatile read&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;size&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(n)&lt;/strong&gt;, 부정확&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;약함&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;사용-사례&quot;&gt;사용 사례&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;양 끝에서 동시 작업이 일어나는 큐&lt;/strong&gt; (예: 일부 work-stealing 패턴)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;stack + queue 혼용 동시성&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;concurrentlinkedqueue-와의-선택&quot;&gt;ConcurrentLinkedQueue 와의 선택&lt;/h2&gt;
&lt;p&gt;대부분의 경우 &lt;code&gt;ConcurrentLinkedQueue&lt;/code&gt; 가 충분. &lt;strong&gt;양쪽 끝 연산이 모두 필요할 때만&lt;/strong&gt; Deque 선택.&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;시나리오&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;권장&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;FIFO 만&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;[[ConcurrentLinkedQueue]]&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;양 끝 add/remove&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;ConcurrentLinkedDeque&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Producer-Consumer (blocking)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;[[BlockingQueue]] 구현체&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[Object]]&lt;/li&gt;
&lt;li&gt;[[Iterable]]&lt;/li&gt;
&lt;li&gt;[[Collection]]&lt;/li&gt;
&lt;li&gt;[[Queue]]&lt;/li&gt;
&lt;li&gt;[[Deque]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentLinkedQueue]]&lt;/li&gt;
&lt;li&gt;[[BlockingQueue]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>concurrent</category><category>deque</category><category>lock-free</category><author>koa (김신건)</author></item><item><title>[Java] ConcurrentLinkedQueue</title><link>https://shinkeonkim.com/wiki/java/java-concurrentlinkedqueue/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-concurrentlinkedqueue/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.concurrent.ConcurrentLinkedQueue&amp;#x3C;E&gt;&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;lock-free&lt;/strong&gt; 로 구현된 unbounded thread-safe [[Queue]]. Michael &amp;#x26; Scott 의 non-blocking queue 알고리즘 (1996) 기반.&lt;/p&gt;
&lt;p&gt;[[BlockingQueue]] 가 아닌 단순 큐. 큐가 비어 있으면 &lt;code&gt;poll()&lt;/code&gt; 이 즉시 &lt;code&gt;null&lt;/code&gt; 반환 (block 하지 않음).&lt;/p&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;내부-구조&quot;&gt;내부 구조&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ConcurrentLinkedQueue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; ... {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; transient&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; volatile&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; head;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; transient&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; volatile&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; tail;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        volatile&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; E item;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        volatile&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; next;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;head&lt;/code&gt;, &lt;code&gt;tail&lt;/code&gt;, &lt;code&gt;item&lt;/code&gt;, &lt;code&gt;next&lt;/code&gt; 모두 &lt;code&gt;volatile&lt;/code&gt;. 모든 갱신이 [[volatile]] write/CAS 로 수행돼 lock-free.&lt;/p&gt;
&lt;h2 id=&quot;offer-의-흐름-michael--scott&quot;&gt;offer 의 흐름 (Michael &amp;#x26; Scott)&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;offer(x):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  newNode = Node(x)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  loop:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    t = tail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    next = t.next&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if (next == null) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // tail 의 next 가 비어있음, 여기에 CAS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      if (CAS(t.next, null, newNode)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        CAS(tail, t, newNode)         // tail 이동 (best-effort)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;        return&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    } else {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      // 다른 스레드가 추가했지만 tail 이 아직 안 옮겨짐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      CAS(tail, t, next)               // 도와서 tail 이동&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;핵심: &lt;strong&gt;tail 이동이 best-effort&lt;/strong&gt;, 즉 다른 스레드가 도와서 옮길 수 있다. 따라서 어떤 스레드든 큐의 일관성을 유지.&lt;/p&gt;
&lt;h2 id=&quot;poll-의-흐름&quot;&gt;poll 의 흐름&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;poll():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;  loop:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    h = head&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    next = h.next&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if (next == null) return null     // 비어 있음&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    if (CAS(head, h, next)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      e = next.item&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      next.item = null                // GC 친화&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;      return e&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;복잡도&quot;&gt;복잡도&lt;/h2&gt;








































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;작업&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;시간&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;동시성&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;offer(e)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;amortized O(1)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;lock-free, CAS 재시도&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;poll()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;amortized O(1)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;lock-free, CAS 재시도&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;peek()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;volatile read&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;size()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;약함, 정확하지 않을 수 있음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;contains&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;약함&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;순회&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;weakly consistent&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
&lt;strong&gt;&lt;code&gt;size()&lt;/code&gt; 가 O(n) 이고 부정확하다.&lt;/strong&gt; 동시 수정 중에는 정확한 카운트 보장 안 됨. 정확한 개수가 필요하면 외부 카운터.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;blockingqueue-와의-차이&quot;&gt;BlockingQueue 와의 차이&lt;/h2&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;항목&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;ConcurrentLinkedQueue&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;[[BlockingQueue]] (LinkedBlockingQueue 등)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;비어 있을 때 poll&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;즉시 null&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;(take 는) block&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;가득 차 있을 때 offer&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;(unbounded 라 발생 X)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;(put 은) block&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;락&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;lock-free (CAS)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;ReentrantLock&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;백프레셔&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✗ (unbounded)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✓&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;메모리 보호&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✗ (OOM 가능)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✓ (bounded 설정 가능)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;생산자-소비자 같은 패턴에는 &lt;strong&gt;[[BlockingQueue]] 가 보통 더 적합&lt;/strong&gt;. CLQ 는 polling 기반 처리, 비어 있을 때 다른 일 하는 패턴에 적합.&lt;/p&gt;
&lt;h2 id=&quot;사용-예&quot;&gt;사용 예&lt;/h2&gt;
&lt;h3 id=&quot;작업-큐-polling&quot;&gt;작업 큐 (polling)&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Queue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; queue &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ConcurrentLinkedQueue&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Producer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;offer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Consumer (polling)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (running) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Task t &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;poll&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (t &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        Thread.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sleep&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 잠시 쉬고 다시&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        continue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    process&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(t);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;비어 있을 때 즉시 반환되므로 polling 으로 직접 backoff 가능.&lt;/p&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[Object]]&lt;/li&gt;
&lt;li&gt;[[Iterable]]&lt;/li&gt;
&lt;li&gt;[[Collection]]&lt;/li&gt;
&lt;li&gt;[[Queue]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentLinkedDeque]]&lt;/li&gt;
&lt;li&gt;[[BlockingQueue]]&lt;/li&gt;
&lt;li&gt;[[volatile]]&lt;/li&gt;
&lt;li&gt;[[Non-Blocking]]&lt;/li&gt;
&lt;li&gt;Maged M. Michael &amp;#x26; Michael L. Scott, “Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms” (PODC 1996)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>concurrent</category><category>queue</category><category>lock-free</category><category>michael-scott</category><author>koa (김신건)</author></item><item><title>[Java] ConcurrentModificationException</title><link>https://shinkeonkim.com/wiki/java/java-concurrent-modification-exception/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-concurrent-modification-exception/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.ConcurrentModificationException&lt;/code&gt;&lt;/strong&gt; (CME) 는 [[fail-fast iterator]] 가 &lt;strong&gt;컬렉션의 구조 변경을 탐지했을 때&lt;/strong&gt; 던지는 unchecked 예외 (&lt;code&gt;RuntimeException&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;이름과 달리 &lt;strong&gt;반드시 동시성 (멀티스레드) 문제일 때만 발생하는 것이 아니다.&lt;/strong&gt; 단일 스레드에서도 자기 자신을 잘못 수정하면 발생한다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;java.util&lt;/code&gt; 의 거의 모든 컬렉션 ([[ArrayList]], [[LinkedList]], [[Vector]], &lt;code&gt;HashMap&lt;/code&gt;, &lt;code&gt;TreeMap&lt;/code&gt;, &lt;code&gt;HashSet&lt;/code&gt;, &lt;code&gt;TreeSet&lt;/code&gt;) 의 iterator 가 던질 수 있다.&lt;/p&gt;
&lt;h2 id=&quot;가장-흔한-두-시나리오&quot;&gt;가장 흔한 두 시나리오&lt;/h2&gt;
&lt;h3 id=&quot;1-순회-중-자기-수정-단일-스레드&quot;&gt;1. 순회 중 자기 수정 (단일 스레드)&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;(List.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (Integer x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list) {           &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// iterator 사용&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x);            &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ CME 던짐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;for-each&lt;/code&gt; 는 내부적으로 &lt;code&gt;iterator()&lt;/code&gt; 를 호출. 그 iterator 가 만들어진 뒤 &lt;code&gt;list.remove()&lt;/code&gt; 가 &lt;code&gt;modCount&lt;/code&gt; 를 증가시킨다. 다음 &lt;code&gt;it.next()&lt;/code&gt; 에서 검사 실패 → CME.&lt;/p&gt;
&lt;h3 id=&quot;2-멀티스레드-동시-수정&quot;&gt;2. 멀티스레드 동시 수정&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; shared &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Thread A&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (Integer x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; shared) { &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/* 읽기 */&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Thread B (동시 실행)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;shared.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;99&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ← Thread A 의 다음 next() 에서 CME&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 경우 CME 는 best-effort 신호. CME 가 안 나도 안전한 것은 아니다 (더 무서운 [silent corruption] 가능).&lt;/p&gt;
&lt;h2 id=&quot;메시지에-없는-정보&quot;&gt;메시지에 없는 정보&lt;/h2&gt;
&lt;p&gt;CME 의 메시지에는 &lt;strong&gt;누가 수정했는지&lt;/strong&gt; 가 적혀 있지 않다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Exception in thread &quot;main&quot; java.util.ConcurrentModificationException&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1095)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    at java.base/java.util.ArrayList$Itr.next(ArrayList.java:1049)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;    at MyApp.main(MyApp.java:23)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Itr.next()&lt;/code&gt; 가 trigger 일 뿐, 진짜 원인은 &lt;strong&gt;그 사이에 일어난 다른 어딘가의 수정&lt;/strong&gt;. 디버깅을 위해서는:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;iterator 와 같은 스택 위쪽 코드&lt;/strong&gt; 부터 살핀다. 같은 메서드 안에 add/remove 가 있는지.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;공유 컬렉션이라면 다른 스레드의 호출&lt;/strong&gt; 을 추적한다. 보통 lambda, async, scheduled task.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ArrayList&lt;/code&gt; 등에 디버거를 걸어 &lt;code&gt;modCount&lt;/code&gt; 변화를 추적&lt;/strong&gt; 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;해결-패턴&quot;&gt;해결 패턴&lt;/h2&gt;
&lt;h3 id=&quot;iteratorremove-사용&quot;&gt;&lt;code&gt;Iterator.remove()&lt;/code&gt; 사용&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Iterator&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; it &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (it.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;hasNext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Integer x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; it.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        it.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ✓ iterator 가 expectedModCount 도 함께 갱신&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Iterator.remove()&lt;/code&gt; 는 컬렉션의 &lt;code&gt;remove()&lt;/code&gt; 를 호출한 뒤 &lt;code&gt;expectedModCount = modCount&lt;/code&gt; 로 동기화한다. 그래서 CME 가 발생하지 않는다.&lt;/p&gt;
&lt;h3 id=&quot;removeif-사용-java-8&quot;&gt;&lt;code&gt;removeIf&lt;/code&gt; 사용 (Java 8+)&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;removeIf&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;내부적으로 &lt;code&gt;Iterator.remove()&lt;/code&gt; 와 같은 안전한 방식. 더 짧고 명확.&lt;/p&gt;
&lt;h3 id=&quot;복사본-순회&quot;&gt;복사본 순회&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (Integer x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;(list)) {   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 복사본 순회&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x);                     &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ✓ 원본은 수정&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;복사 비용을 감수하는 대신 가장 단순한 해결.&lt;/p&gt;
&lt;h3 id=&quot;동시성-컬렉션-사용&quot;&gt;동시성 컬렉션 사용&lt;/h3&gt;
&lt;p&gt;진짜 멀티스레드 환경이라면 fail-fast 컬렉션 자체를 피한다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 읽기 많음, 쓰기 적음&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; CopyOnWriteArrayList&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 키-값&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Map&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; map &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ConcurrentHashMap&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 큐&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Queue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; q &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ConcurrentLinkedQueue&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이들은 CME 를 던지지 않으면서 동시 수정/순회를 지원한다.&lt;/p&gt;
&lt;h2 id=&quot;잡으면-안-된다&quot;&gt;잡으면 안 된다&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ 안 좋은 패턴&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (Integer x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (cond) list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (ConcurrentModificationException &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // 무시&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 catch 는 &lt;strong&gt;버그를 숨길 뿐&lt;/strong&gt;. iterator 가 일관성 없는 상태로 더 진행하지 않은 것은 다행이지만, 그래도 “왜 동시 수정이 일어났는가” 라는 진짜 문제는 그대로다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
&lt;strong&gt;CME 는 잡지 말고 고쳐라.&lt;/strong&gt; “왜 이게 던져졌는가” 라는 질문에서 출발해 코드의 동시성 가정을 다시 본다. CME 가 사라지도록 위의 해결 패턴 중 하나를 적용.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;자주-만나는-추가-사례&quot;&gt;자주 만나는 추가 사례&lt;/h2&gt;
&lt;h3 id=&quot;streamforeach-도-동일&quot;&gt;&lt;code&gt;Stream.forEach&lt;/code&gt; 도 동일&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stream&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (cond) list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ CME&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;내부적으로 iterator 사용. 같은 함정.&lt;/p&gt;
&lt;h3 id=&quot;hashmap-순회-중-put&quot;&gt;&lt;code&gt;HashMap&lt;/code&gt; 순회 중 &lt;code&gt;put&lt;/code&gt;&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Map&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; map &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; HashMap&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; entry &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;entrySet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;new&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ CME (key 가 새로 추가되면 구조 변경)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;값만 바꾸는 것 (&lt;code&gt;entry.setValue(...)&lt;/code&gt;) 은 OK.&lt;/p&gt;
&lt;h3 id=&quot;nested-loop&quot;&gt;nested loop&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (Integer a &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; listA) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (Integer b &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; listB) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (cond) listA.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(a);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ outer 의 CME&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;자주 놓치는 케이스, outer loop 에 영향.&lt;/p&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[fail-fast iterator]]&lt;/li&gt;
&lt;li&gt;[[ArrayList]]&lt;/li&gt;
&lt;li&gt;[[LinkedList]]&lt;/li&gt;
&lt;li&gt;[[Vector]]&lt;/li&gt;
&lt;li&gt;[[CopyOnWriteArrayList]]&lt;/li&gt;
&lt;li&gt;Brian Goetz, &lt;em&gt;Java Concurrency in Practice&lt;/em&gt;, §5.1.2&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>exception</category><category>iterator</category><category>concurrency</category><category>fail-fast</category><author>koa (김신건)</author></item><item><title>[Java] ConcurrentSkipListMap</title><link>https://shinkeonkim.com/wiki/java/java-concurrentskiplistmap/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-concurrentskiplistmap/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.concurrent.ConcurrentSkipListMap&amp;#x3C;K,V&gt;&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;Skip List&lt;/strong&gt; 기반의 thread-safe 정렬 [[Map]]. [[TreeMap]] 의 동시성 버전.&lt;/p&gt;
&lt;p&gt;[[ConcurrentHashMap]] 과의 결정적 차이: &lt;strong&gt;정렬 순서를 유지&lt;/strong&gt; + &lt;code&gt;NavigableMap&lt;/code&gt; 인터페이스 구현 (&lt;code&gt;floor&lt;/code&gt;, &lt;code&gt;ceiling&lt;/code&gt;, &lt;code&gt;subMap&lt;/code&gt; 등).&lt;/p&gt;
&lt;p&gt;Skip List 는 평균 O(log n) 의 균형 트리 대체 자료구조. 락 없이 동시 수정이 가능한 알고리즘이 잘 알려져 있어 동시성 구현에 적합.&lt;/p&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;skip-list-의-구조&quot;&gt;Skip List 의 구조&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;text&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Level 3: head ─────────────────────► 25 ─────────► null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Level 2: head ────────► 10 ────────► 25 ──► 40 ──► null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Level 1: head ─► 5 ──► 10 ──► 17 ──► 25 ──► 40 ──► null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Level 0: head ─► 5 ──► 10 ──► 17 ──► 25 ──► 33 ── 40 ─► null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                            ↑&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;                                    실제 데이터 lane&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;각 노드가 확률적으로 여러 레벨에 포함&lt;/li&gt;
&lt;li&gt;상위 레벨은 “스킵 인덱스” 처럼 작용해 O(log n) 검색&lt;/li&gt;
&lt;li&gt;새 노드 삽입 시 동전 던지듯 레벨 결정 (1/2 확률로 한 레벨씩 위로)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;복잡도&quot;&gt;복잡도&lt;/h2&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;작업&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;평균&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;최악&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;get&lt;/code&gt;, &lt;code&gt;put&lt;/code&gt;, &lt;code&gt;remove&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(log n)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n) (매우 드뭄, 동전이 다 같은 면)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;firstKey&lt;/code&gt;, &lt;code&gt;lastKey&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;containsKey&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(log n)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;순회&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;size()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;약함&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;사용-예&quot;&gt;사용 예&lt;/h2&gt;
&lt;h3 id=&quot;시간순-정렬된-동시성-맵&quot;&gt;시간순 정렬된 동시성 맵&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ConcurrentNavigableMap&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Instant&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Event&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; log &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ConcurrentSkipListMap&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Producer thread&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;log.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Instant.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), event);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Consumer thread&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;NavigableMap&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Instant&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Event&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; recent &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; log.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;tailMap&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Instant.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;now&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;().&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;minusSeconds&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;60&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;recent.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;((t, e) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; process&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(e));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;range-쿼리--동시성&quot;&gt;Range 쿼리 + 동시성&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ConcurrentNavigableMap&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; levels &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ConcurrentSkipListMap&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;levels.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;free&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;levels.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;basic&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;levels.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;premium&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 어느 등급에 해당하는지&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;String tier &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; levels.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;floorEntry&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(user.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;points&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getValue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;concurrenthashmap-vs-concurrentskiplistmap&quot;&gt;ConcurrentHashMap vs ConcurrentSkipListMap&lt;/h2&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;항목&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;ConcurrentHashMap&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;ConcurrentSkipListMap&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;get/put 시간&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(1) 평균&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(log n)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;순서&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;없음&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;정렬&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Range 쿼리&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓ (subMap 등)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;floor / ceiling&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;동시성 메커니즘&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;CAS + 버킷 sync&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;lock-free skip list&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;순서가 중요하지 않으면 ConcurrentHashMap, 정렬/범위 쿼리가 필요하면 ConcurrentSkipListMap.&lt;/p&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[Object]]&lt;/li&gt;
&lt;li&gt;[[Iterable]]&lt;/li&gt;
&lt;li&gt;[[Collection]]&lt;/li&gt;
&lt;li&gt;[[Map]]&lt;/li&gt;
&lt;li&gt;[[TreeMap]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentHashMap]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentSkipListSet]]&lt;/li&gt;
&lt;li&gt;[[Non-Blocking]]&lt;/li&gt;
&lt;li&gt;William Pugh, “Skip Lists: A Probabilistic Alternative to Balanced Trees” (CACM 1990)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>concurrent</category><category>map</category><category>skip-list</category><category>sorted</category><category>lock-free</category><author>koa (김신건)</author></item><item><title>[Java] ConcurrentSkipListSet</title><link>https://shinkeonkim.com/wiki/java/java-concurrentskiplistset/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-concurrentskiplistset/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.concurrent.ConcurrentSkipListSet&amp;#x3C;E&gt;&lt;/code&gt;&lt;/strong&gt; 는 [[ConcurrentSkipListMap]] 을 백킹으로 사용하는 &lt;strong&gt;정렬된 thread-safe [[Set]]&lt;/strong&gt;. [[TreeSet]] 의 동시성 버전.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;NavigableSet&lt;/code&gt; 인터페이스 구현. floor, ceiling, subSet 등 정렬 기반 연산 제공.&lt;/p&gt;
&lt;h2 id=&quot;복잡도&quot;&gt;복잡도&lt;/h2&gt;
&lt;p&gt;[[ConcurrentSkipListMap]] 의 성질.&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;작업&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;평균&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;add&lt;/code&gt;, &lt;code&gt;remove&lt;/code&gt;, &lt;code&gt;contains&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(log n)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;first&lt;/code&gt;, &lt;code&gt;last&lt;/code&gt;, &lt;code&gt;floor&lt;/code&gt;, &lt;code&gt;ceiling&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(log n)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;size&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n), 부정확&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;사용-예&quot;&gt;사용 예&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;NavigableSet&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; sorted &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ConcurrentSkipListSet&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sorted.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;); sorted.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;); sorted.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;30&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sorted.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;floor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;15&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 10&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sorted.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ceiling&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;15&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);              &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;sorted.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;subSet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;30&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);           &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// [10, 30)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;hashset--treeset--concurrentskiplistset&quot;&gt;HashSet / TreeSet / ConcurrentSkipListSet&lt;/h2&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;항목&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;HashSet&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;TreeSet&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;ConcurrentSkipListSet&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;시간&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(log n)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(log n)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;정렬&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Thread-safe&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Range 쿼리&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[Object]]&lt;/li&gt;
&lt;li&gt;[[Iterable]]&lt;/li&gt;
&lt;li&gt;[[Collection]]&lt;/li&gt;
&lt;li&gt;[[Set]]&lt;/li&gt;
&lt;li&gt;[[Map]]&lt;/li&gt;
&lt;li&gt;[[TreeSet]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentSkipListMap]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>concurrent</category><category>set</category><category>skip-list</category><category>sorted</category><author>koa (김신건)</author></item><item><title>[Java] CopyOnWriteArrayList</title><link>https://shinkeonkim.com/wiki/java/java-copyonwritearraylist/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-copyonwritearraylist/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.concurrent.CopyOnWriteArrayList&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;쓰기 시 배열 전체를 복사&lt;/strong&gt; 하는 thread-safe [[List]] 구현. &lt;strong&gt;읽기에는 lock 이 전혀 없고&lt;/strong&gt;, 쓰기에는 &lt;code&gt;ReentrantLock&lt;/code&gt; 으로 직렬화한다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;java.util.concurrent&lt;/code&gt; (JSR-166) 의 컬렉션. &lt;strong&gt;읽기 압도적 다, 쓰기 거의 없음&lt;/strong&gt; 인 시나리오 (예: 이벤트 리스너 목록, 옵저버 패턴, 설정 캐시) 에 가장 적합.&lt;/p&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;내부-구조&quot;&gt;내부 구조&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CopyOnWriteArrayList&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RandomAccess&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Cloneable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, java.io.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Serializable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; transient&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ReentrantLock lock &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ReentrantLock&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; transient&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; volatile&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] array;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getArray&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; array; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; setArray&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Object&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { array &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; a; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;핵심 두 가지.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;array&lt;/code&gt; 는 &lt;code&gt;volatile&lt;/code&gt;&lt;/strong&gt;: 한 스레드의 &lt;code&gt;setArray()&lt;/code&gt; 가 다른 스레드의 &lt;code&gt;getArray()&lt;/code&gt; 에 즉시 보인다. 별도 락 없이 새 배열 참조가 publish 된다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;lock&lt;/code&gt; 은 쓰기 직렬화용&lt;/strong&gt;: 동시에 두 쓰기가 진행되지 않도록만 보장. 읽기에는 관여하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;읽기-lock-없이&quot;&gt;읽기, lock 없이&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; E &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; index) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; elementAt&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getArray&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), index);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;getArray()&lt;/code&gt; 로 현재 배열 참조를 한 번 읽고, 그 배열의 인덱스 자리를 반환한다. &lt;strong&gt;lock 도, 동기화 블록도 없다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;스레드가 100 개라도 모두 자기 CPU 의 캐시로 &lt;code&gt;volatile&lt;/code&gt; 읽기 1 번을 수행할 뿐. 사실상 ArrayList 만큼 빠르다.&lt;/p&gt;
&lt;h2 id=&quot;쓰기-전체-복사&quot;&gt;쓰기, 전체 복사&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(E e) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ReentrantLock lock &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.lock;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    lock.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;lock&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        Object&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] elements &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getArray&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; len &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; elements.length;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        Object&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;[] newElements &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Arrays.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;copyOf&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(elements, len &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// O(n)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        newElements[len] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; e;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        setArray&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(newElements);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        lock.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unlock&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;락 획득&lt;/strong&gt;: 다른 쓰기를 막는다 (읽기는 그대로 진행 가능)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Arrays.copyOf&lt;/code&gt;&lt;/strong&gt;: &lt;strong&gt;전체 배열을 통째로 복사&lt;/strong&gt;. O(n) 비용.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;수정&lt;/strong&gt;: 새 배열에 원소 추가&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;setArray&lt;/code&gt;&lt;/strong&gt;: 새 배열 참조로 교체. 이 한 순간에 모든 후속 읽기가 새 배열을 보게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;remove&lt;/code&gt;, &lt;code&gt;set&lt;/code&gt; 도 같은 패턴. 모든 쓰기가 &lt;strong&gt;O(n) 복사&lt;/strong&gt; 를 동반한다.&lt;/p&gt;
&lt;h2 id=&quot;주요-연산-비용&quot;&gt;주요 연산 비용&lt;/h2&gt;



























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;메서드&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;시간&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;락&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;비고&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;get(int i)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;없음&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;volatile read 1 번&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;size()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;없음&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;iterator()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;없음&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;snapshot 반환&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;add(E)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;쓰기 락&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;배열 전체 복사&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;add(int i, E)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;쓰기 락&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;복사 + shift&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;remove(int i)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;쓰기 락&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;복사 + shift&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;set(int i, E)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(n)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;쓰기 락&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;한 자리만 바뀌어도 복사&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;addAll(Collection)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(n + m)&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;쓰기 락 한 번&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;묶어서 처리&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!TIP]
여러 원소를 한 번에 추가할 때는 &lt;code&gt;addAll(...)&lt;/code&gt; 을 쓰자. 각각 &lt;code&gt;add&lt;/code&gt; 하면 n 회의 전체 복사가 발생하지만, &lt;code&gt;addAll&lt;/code&gt; 은 한 번의 복사로 끝난다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;snapshot-iterator&quot;&gt;Snapshot Iterator&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;CopyOnWriteArrayList&lt;/code&gt; 의 iterator 는 생성 시점의 배열 참조를 그대로 들고 다닌다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; CopyOnWriteArrayList&amp;#x3C;&gt;(List.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;A&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;B&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;C&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Iterator&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; it &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;D&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 새 배열로 교체됨&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (it.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;hasNext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(it.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// A, B, C 만 출력 (D 는 보이지 않음)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;장점:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ConcurrentModificationException&lt;/code&gt; 없음&lt;/strong&gt;, 순회 중 다른 스레드가 수정해도 안전&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;순회 중 수정 자유&lt;/strong&gt;, 단 그 수정은 다음 순회부터 보임&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;단점:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;it.remove()&lt;/code&gt;, &lt;code&gt;it.set(E)&lt;/code&gt;, &lt;code&gt;it.add(E)&lt;/code&gt; 모두 &lt;code&gt;UnsupportedOperationException&lt;/code&gt;&lt;/strong&gt;, iterator 는 read-only&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;메모리-관점&quot;&gt;메모리 관점&lt;/h2&gt;
&lt;p&gt;쓰기가 일어날 때마다 &lt;strong&gt;두 배열이 동시에 존재&lt;/strong&gt; 한다 (기존 + 새것). GC 가 기존 배열을 회수할 때까지는 메모리 2 배 사용.&lt;/p&gt;
&lt;p&gt;또한 진행 중인 iterator 가 기존 배열을 참조하고 있다면 그것도 살아 있어야 한다. 긴 iterator 가 많은 환경에서는 메모리 사용량이 더 늘어날 수 있다.&lt;/p&gt;
&lt;h2 id=&quot;언제-copyonwritearraylist-가-답인가&quot;&gt;언제 CopyOnWriteArrayList 가 답인가&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;읽기 &gt;&gt; 쓰기&lt;/strong&gt; 시나리오에서 최적이다.&lt;/p&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;패턴&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;적합도&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;이벤트 리스너 목록&lt;/strong&gt; (등록 드물고 발화 잦음)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐⭐&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;옵저버 패턴 구독자 목록&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐⭐&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;설정 / 메타데이터 캐시&lt;/strong&gt; (변경 드묾)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐⭐&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;읽기 위주의 작은 리스트&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐⭐&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;쓰기 빈도 적당&lt;/strong&gt;, 컬렉션이 작음&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⭐&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;쓰기 빈도 높음 / 컬렉션 큼&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗ (&lt;code&gt;ConcurrentLinkedQueue&lt;/code&gt;, &lt;code&gt;Collections.synchronizedList&lt;/code&gt; 등 고려)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
1000 개 원소 리스트에 매초 100 번 add 한다면 CoW 는 &lt;strong&gt;매초 100,000 회 배열 복사 = 10MB+ 메모리 트래픽&lt;/strong&gt;. 이런 워크로드에서는 사용 금지.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;다른-동시성-list-와의-비교&quot;&gt;다른 동시성 List 와의 비교&lt;/h2&gt;








































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;옵션&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;읽기&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;쓰기&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;메모리&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;iterator&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;CopyOnWriteArrayList&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;lock-free&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n) 복사&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;쓰기 시 2x&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;snapshot, CME 없음&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;&lt;code&gt;Collections.synchronizedList(arraylist)&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;락&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;락&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;동일&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;외부 동기화 필요, fail-fast&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[[Vector]]&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;락&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;락&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;동일&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;외부 동기화 필요, fail-fast&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;&lt;code&gt;ConcurrentLinkedDeque&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;lock-free&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;lock-free&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;노드 오버헤드&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;weakly consistent&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[Object]]&lt;/li&gt;
&lt;li&gt;[[Iterable]]&lt;/li&gt;
&lt;li&gt;[[Collection]]&lt;/li&gt;
&lt;li&gt;[[List]]&lt;/li&gt;
&lt;li&gt;[[ArrayList]]&lt;/li&gt;
&lt;li&gt;[[Vector]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentHashMap]]&lt;/li&gt;
&lt;li&gt;[[volatile]]&lt;/li&gt;
&lt;li&gt;[[ReentrantLock]]&lt;/li&gt;
&lt;li&gt;[[fail-fast iterator]]&lt;/li&gt;
&lt;li&gt;[[Non-Blocking]]&lt;/li&gt;
&lt;li&gt;Brian Goetz, &lt;em&gt;Java Concurrency in Practice&lt;/em&gt;, §5.2 Copy-on-Write Collections&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>collection</category><category>data-structure</category><category>list</category><category>concurrent</category><category>thread-safe</category><category>copy-on-write</category><author>koa (김신건)</author></item><item><title>[Java] CopyOnWriteArraySet</title><link>https://shinkeonkim.com/wiki/java/java-copyonwritearrayset/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-copyonwritearrayset/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.concurrent.CopyOnWriteArraySet&amp;#x3C;E&gt;&lt;/code&gt;&lt;/strong&gt; 는 [[CopyOnWriteArrayList]] 를 백킹으로 사용하는 thread-safe [[Set]]. 중복 검사를 위해 매 add 마다 &lt;code&gt;contains&lt;/code&gt; (O(n)) 를 수행.&lt;/p&gt;
&lt;p&gt;[[CopyOnWriteArrayList]] 의 모든 특성 (snapshot iterator, 읽기 lock-free, 쓰기 시 전체 복사) 을 물려받는다.&lt;/p&gt;
&lt;h2 id=&quot;내부-구조&quot;&gt;내부 구조&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CopyOnWriteArraySet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AbstractSet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; ... {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; CopyOnWriteArrayList&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; al;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(E &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; al.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;addIfAbsent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(e);    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 선형 검색 후 없으면 추가&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;복잡도&quot;&gt;복잡도&lt;/h2&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;작업&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;시간&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;add(e)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;&lt;strong&gt;O(n)&lt;/strong&gt; (검색 + 전체 복사)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;contains(o)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n) (선형 검색)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;remove(o)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n) (검색 + 복사)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;순회&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n) (snapshot)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!CAUTION]
&lt;strong&gt;add 가 O(n)&lt;/strong&gt; 이다. n 이 작거나 (수십 이하), 쓰기가 거의 없는 경우에만 사용. n 이 크면 [[ConcurrentHashMap]] 의 &lt;code&gt;newKeySet()&lt;/code&gt; 또는 &lt;code&gt;Collections.synchronizedSet(new HashSet&amp;#x3C;&gt;())&lt;/code&gt; 이 훨씬 빠르다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;사용-사례&quot;&gt;사용 사례&lt;/h2&gt;
&lt;p&gt;[[CopyOnWriteArrayList]] 와 동일한 패턴.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;이벤트 리스너 집합&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;옵저버 패턴 구독자&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;설정 / 메타데이터 집합&lt;/strong&gt;, 변경 드묾&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;동시성-set-비교&quot;&gt;동시성 Set 비교&lt;/h2&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;옵션&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;add&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;contains&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;iterator&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;CopyOnWriteArraySet&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;O(n) + 전체 복사&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;O(n)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;snapshot&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;ConcurrentHashMap.newKeySet()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;O(1) avg&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;O(1) avg&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;weakly consistent&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;Collections.synchronizedSet(HashSet)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;O(1) + 락&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;O(1) + 락&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;fail-fast (외부 동기화 필요)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;ConcurrentSkipListSet&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;O(log n)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;O(log n)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;weakly consistent, 정렬&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[Object]]&lt;/li&gt;
&lt;li&gt;[[Iterable]]&lt;/li&gt;
&lt;li&gt;[[Collection]]&lt;/li&gt;
&lt;li&gt;[[Set]]&lt;/li&gt;
&lt;li&gt;[[CopyOnWriteArrayList]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentHashMap]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentSkipListSet]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>concurrent</category><category>set</category><category>copy-on-write</category><author>koa (김신건)</author></item><item><title>[Java] CountDownLatch</title><link>https://shinkeonkim.com/wiki/java/java-countdown-latch/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-countdown-latch/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.concurrent.CountDownLatch&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;한 스레드 또는 여러 스레드가 다른 스레드들의 작업 완료를 기다리는&lt;/strong&gt; 일회용 synchronizer.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;N&lt;/code&gt; 으로 초기화하고, 각 worker 가 작업 후 &lt;code&gt;countDown()&lt;/code&gt; 호출. waiter 는 &lt;code&gt;await()&lt;/code&gt; 로 count 가 0 이 될 때까지 [[Blocking]]. &lt;strong&gt;0 이 되면 다시 1 로 돌릴 수 없음&lt;/strong&gt;, 일회용.&lt;/p&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;핵심-메서드&quot;&gt;핵심 메서드&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;CountDownLatch latch &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CountDownLatch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(N);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;latch.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;countDown&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();              &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// count - 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;latch.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// count == 0 될 때까지 block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;latch.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(timeout, unit);     &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// timeout 까지만 block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;latch.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getCount&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();               &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 현재 count (참고용)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;가장-흔한-두-패턴&quot;&gt;가장 흔한 두 패턴&lt;/h2&gt;
&lt;h3 id=&quot;1-main-스레드가-n-개-작업-완료-대기&quot;&gt;1. main 스레드가 N 개 작업 완료 대기&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;ExecutorService pool &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Executors.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;newFixedThreadPool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(N);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;CountDownLatch done &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CountDownLatch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(N);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; N; i&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    pool.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;submit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;doWork&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        finally&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { done.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;countDown&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); }   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 반드시 finally&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;done.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 모든 작업 끝날 때까지 block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;all done&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-시작-신호-start-gate&quot;&gt;2. 시작 신호 (start gate)&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;CountDownLatch startGate &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CountDownLatch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; N; i&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Thread&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        startGate.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();              &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// start 신호 대기&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 준비 완료 시&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;startGate.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;countDown&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 모든 스레드 동시 출발&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;부하 테스트 도구 (JMeter, Gatling 의 ramp-up) 와 비슷한 패턴.&lt;/p&gt;
&lt;h2 id=&quot;countdownlatch-vs-cyclicbarrier&quot;&gt;CountDownLatch vs CyclicBarrier&lt;/h2&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;항목&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;CountDownLatch&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;[[CyclicBarrier]]&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;사용 횟수&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;일회용&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;재사용 가능&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;누가 기다리는가&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;한 명 또는 여러 명&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;모두가 서로 기다림&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;도착 콜백&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;없음&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;barrier action 실행 가능&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;reset&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;불가&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;reset()&lt;/code&gt; 가능&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;CountDownLatch 는 비대칭 (1 -&gt; N 또는 N -&gt; 1), CyclicBarrier 는 대칭 (N -&gt; N 만남).&lt;/p&gt;
&lt;h2 id=&quot;함정&quot;&gt;함정&lt;/h2&gt;
&lt;h3 id=&quot;1-0-이후-다시-못-쓴다&quot;&gt;1. 0 이후 다시 못 쓴다&lt;/h3&gt;
&lt;p&gt;재사용이 필요하면 [[CyclicBarrier]] 또는 [[Phaser]].&lt;/p&gt;
&lt;h3 id=&quot;2-countdown-빠뜨리면-영원히-block&quot;&gt;2. countDown 빠뜨리면 영원히 block&lt;/h3&gt;
&lt;p&gt;worker 가 예외로 종료되면서 &lt;code&gt;countDown&lt;/code&gt; 을 호출 안 하면 main 이 영영 대기. &lt;strong&gt;항상 &lt;code&gt;finally&lt;/code&gt; 블록에서 호출.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[CyclicBarrier]]&lt;/li&gt;
&lt;li&gt;[[Semaphore]]&lt;/li&gt;
&lt;li&gt;[[Phaser]]&lt;/li&gt;
&lt;li&gt;[[Blocking]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>concurrent</category><category>synchronizer</category><category>latch</category><author>koa (김신건)</author></item><item><title>[Java] CyclicBarrier</title><link>https://shinkeonkim.com/wiki/java/java-cyclic-barrier/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-cyclic-barrier/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.concurrent.CyclicBarrier&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;N 개의 스레드가 모두 도착할 때까지 서로 기다리는&lt;/strong&gt; synchronizer. 모두 도착하면 동시에 출발, 다시 사용 가능 (cyclic).&lt;/p&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;핵심-메서드&quot;&gt;핵심 메서드&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;CyclicBarrier barrier &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CyclicBarrier&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(N);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;CyclicBarrier withAction &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CyclicBarrier&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(N, () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // 모두 도착 시 한 번 실행되는 action&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;all arrived&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;barrier.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 도착, 다른 스레드도 도착할 때까지 block&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;barrier.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(timeout, unit);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;barrier.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getNumberWaiting&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();        &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 현재 대기 중인 스레드 수&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;barrier.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;reset&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 모든 대기자 깨우고 BrokenBarrierException 던짐&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;가장-흔한-패턴-단계별-동시-실행&quot;&gt;가장 흔한 패턴, 단계별 동시 실행&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;CyclicBarrier barrier &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CyclicBarrier&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; i&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Thread&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; phase &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; phase &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; phase&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;            doPhaseWork&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(phase);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            barrier.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 다른 3 스레드 도착 대기&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;            // 모두 같은 phase 완료 후 다음 phase 진입&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;병렬 계산의 각 phase 가 모두 끝나야 다음 phase 시작 가능한 경우 (예: 시뮬레이션 stepping).&lt;/p&gt;
&lt;h2 id=&quot;brokenbarrierexception&quot;&gt;BrokenBarrierException&lt;/h2&gt;
&lt;p&gt;한 스레드가 &lt;code&gt;await&lt;/code&gt; 도중 인터럽트되거나 timeout 되거나 &lt;code&gt;reset()&lt;/code&gt; 호출되면 &lt;strong&gt;다른 모든 대기자가 &lt;code&gt;BrokenBarrierException&lt;/code&gt; 으로 깨어남&lt;/strong&gt;. 한 명이 broken 이면 모두 broken.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    barrier.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (InterruptedException | BrokenBarrierException &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // 처리&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;countdownlatch-vs-cyclicbarrier-vs-phaser&quot;&gt;CountDownLatch vs CyclicBarrier vs Phaser&lt;/h2&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;항목&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;[[CountDownLatch]]&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;CyclicBarrier&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;[[Phaser]]&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;재사용&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✓&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;대칭&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;비대칭 (N → 0)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;대칭 (N 만남)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;대칭 + 동적&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;참여자 수&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;고정&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;고정&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;동적&lt;/strong&gt; (register/deregister)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;콜백&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;barrier action&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;onAdvance hook&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;도입&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;JDK 1.5&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;JDK 1.5&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;JDK 1.7&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;code&gt;CyclicBarrier&lt;/code&gt; 는 N 이 고정이지만 반복, &lt;code&gt;Phaser&lt;/code&gt; 는 N 이 매 phase 마다 바뀔 수 있다.&lt;/p&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[CountDownLatch]]&lt;/li&gt;
&lt;li&gt;[[Phaser]]&lt;/li&gt;
&lt;li&gt;[[Semaphore]]&lt;/li&gt;
&lt;li&gt;[[Blocking]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>concurrent</category><category>synchronizer</category><category>barrier</category><author>koa (김신건)</author></item><item><title>[Java] DelayQueue</title><link>https://shinkeonkim.com/wiki/java/java-delayqueue/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-delayqueue/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.concurrent.DelayQueue&amp;#x3C;E extends Delayed&gt;&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;각 원소가 지정된 delay 가 만료된 후에만&lt;/strong&gt; 꺼낼 수 있는 [[BlockingQueue]]. 우선순위는 만료 시각이 빠른 것부터.&lt;/p&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;delayed-인터페이스&quot;&gt;Delayed 인터페이스&lt;/h2&gt;
&lt;p&gt;원소는 &lt;code&gt;Delayed&lt;/code&gt; 인터페이스를 구현해야 한다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Delayed&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Comparable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Delayed&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    long&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getDelay&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(TimeUnit &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;unit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; DelayedTask&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Delayed&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; readyAt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Runnable job;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; DelayedTask&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; delayMs&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, Runnable &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;job&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.readyAt &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; System.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; delayMs;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;        this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.job &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; job;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; long&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getDelay&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(TimeUnit &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;unit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; unit.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;convert&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(readyAt &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; System.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), TimeUnit.MILLISECONDS);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; compareTo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Delayed &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;o&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Long.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;compare&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.readyAt, ((DelayedTask) o).readyAt);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { job.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;동작&quot;&gt;동작&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;DelayQueue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;DelayedTask&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; q &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; DelayQueue&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;q.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; DelayedTask&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;5초 뒤&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;q.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; DelayedTask&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;1초 뒤&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;DelayedTask t &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; q.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;take&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 1초 뒤에 반환&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;t.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;t &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; q.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;take&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();               &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 추가로 4초 뒤&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;t.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;take()&lt;/code&gt; 는 큐의 가장 앞 원소의 &lt;code&gt;getDelay&lt;/code&gt; 가 ≤ 0 이 될 때까지 block.&lt;/p&gt;
&lt;h2 id=&quot;사용-사례&quot;&gt;사용 사례&lt;/h2&gt;
&lt;h3 id=&quot;스케줄러&quot;&gt;스케줄러&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ScheduledThreadPoolExecutor&lt;/code&gt; 내부에서 비슷한 자료구조 (&lt;code&gt;DelayedWorkQueue&lt;/code&gt;) 를 사용. 일정 시간 뒤 실행되는 작업을 관리.&lt;/p&gt;
&lt;h3 id=&quot;캐시-만료-ttl&quot;&gt;캐시 만료 (TTL)&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CacheEntry&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Delayed&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; String key;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; expiresAt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // getDelay, compareTo ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;DelayQueue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;CacheEntry&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; expirations &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; DelayQueue&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 별도 스레드가 만료된 entry 를 캐시에서 제거&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Thread&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        CacheEntry e &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; expirations.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;take&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        cache.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(e.key);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 캐시 add 시&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;expirations.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; CacheEntry&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;k&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, now &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ttl));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;cache.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;k&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, v);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;retry-큐&quot;&gt;Retry 큐&lt;/h3&gt;
&lt;p&gt;실패한 요청을 일정 시간 뒤 재시도.&lt;/p&gt;
&lt;h2 id=&quot;복잡도&quot;&gt;복잡도&lt;/h2&gt;
&lt;p&gt;내부는 [[PriorityQueue]] (heap).&lt;/p&gt;





















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;작업&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;시간&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;put&lt;/code&gt;, &lt;code&gt;offer&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(log n)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;take&lt;/code&gt;, &lt;code&gt;poll&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(log n)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;peek&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[BlockingQueue]]&lt;/li&gt;
&lt;li&gt;[[PriorityQueue]]&lt;/li&gt;
&lt;li&gt;[[Blocking]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>concurrent</category><category>queue</category><category>blocking</category><category>delay</category><category>scheduling</category><author>koa (김신건)</author></item><item><title>[Java] Deque</title><link>https://shinkeonkim.com/wiki/java/java-deque/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-deque/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.Deque&amp;#x3C;E&gt;&lt;/code&gt;&lt;/strong&gt; (Double-Ended Queue) 는 [[Queue]] 의 확장 인터페이스. &lt;strong&gt;양쪽 끝 (head, tail) 모두에서&lt;/strong&gt; add/remove/examine 가능한 자료구조.&lt;/p&gt;
&lt;p&gt;JDK 1.6 도입. &lt;code&gt;Queue&lt;/code&gt;, &lt;code&gt;Stack&lt;/code&gt;, 일반 List 의 양 끝 연산을 모두 한 인터페이스로 통합.&lt;/p&gt;
&lt;h2 id=&quot;메서드-매트릭스&quot;&gt;메서드 매트릭스&lt;/h2&gt;













































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;위치&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;insert (throw)&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;insert (특수값)&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;remove (throw)&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;remove (특수값)&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;examine&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;head&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;addFirst(e)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;offerFirst(e)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;removeFirst()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;pollFirst()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;peekFirst()&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;tail&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;addLast(e)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;offerLast(e)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;removeLast()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;pollLast()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;peekLast()&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Queue (= tail/head)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;add(e)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;offer(e)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;remove()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;poll()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;peek()&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Stack (= head)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;push(e)&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;(= addFirst)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;pop()&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;(= removeFirst)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;peek()&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;code&gt;push&lt;/code&gt; / &lt;code&gt;pop&lt;/code&gt; 이 head 쪽에 동작하는 점이 중요. Stack 으로 쓸 때 head 가 top 이 된다.&lt;/p&gt;
&lt;h2 id=&quot;구현체&quot;&gt;구현체&lt;/h2&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;구현&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;특징&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[[ArrayDeque]]&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;권장 기본&lt;/strong&gt;, 원형 배열&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[[LinkedList]]&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;양방향 연결 리스트, 메모리 多&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;[[ConcurrentLinkedDeque]]&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;thread-safe (lock-free)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;&lt;code&gt;LinkedBlockingDeque&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;thread-safe + blocking&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
&lt;strong&gt;새 코드의 Stack 은 &lt;code&gt;Deque&amp;#x3C;E&gt; stack = new ArrayDeque&amp;#x3C;&gt;()&lt;/code&gt; 가 권장.&lt;/strong&gt; 레거시 &lt;code&gt;java.util.Stack&lt;/code&gt; 은 Vector 상속이라 비효율적.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Stack 패턴&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Deque&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; stack &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayDeque&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;stack.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;); stack.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;); stack.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;push&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;stack.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;peek&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;stack.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;pop&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();     &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Queue 패턴&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Deque&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; queue &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayDeque&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;offer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;); queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;offer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;); queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;offer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;peek&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;queue.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;poll&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[Object]]&lt;/li&gt;
&lt;li&gt;[[Iterable]]&lt;/li&gt;
&lt;li&gt;[[Collection]]&lt;/li&gt;
&lt;li&gt;[[Queue]]&lt;/li&gt;
&lt;li&gt;[[ArrayDeque]]&lt;/li&gt;
&lt;li&gt;[[LinkedList]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentLinkedDeque]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>collection</category><category>queue</category><category>deque</category><category>interface</category><author>koa (김신건)</author></item><item><title>[Java] Fail-Fast Iterator</title><link>https://shinkeonkim.com/wiki/java/java-fail-fast-iterator/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-fail-fast-iterator/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Fail-Fast Iterator&lt;/strong&gt; 는 &lt;strong&gt;순회 도중 컬렉션의 구조가 변경되면 즉시 &lt;code&gt;ConcurrentModificationException&lt;/code&gt; 을 던지는&lt;/strong&gt; iterator. [[List]], &lt;code&gt;Set&lt;/code&gt;, &lt;code&gt;Map&lt;/code&gt; 등 대부분의 &lt;code&gt;java.util&lt;/code&gt; 컬렉션의 iterator 가 이 방식.&lt;/p&gt;
&lt;p&gt;목적은 단순하다, &lt;strong&gt;나중에 발견되면 디버깅이 끔찍하게 어려울 정합성 위배를, 가능한 가장 이른 시점에 노출&lt;/strong&gt; 시키는 것이다. 실패 자체를 빠르게 만든다는 뜻에서 fail-fast.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;java.util.concurrent&lt;/code&gt; 의 컬렉션 ([[CopyOnWriteArrayList]], &lt;code&gt;ConcurrentHashMap&lt;/code&gt;, &lt;code&gt;ConcurrentLinkedQueue&lt;/code&gt; 등) 은 일부러 fail-fast 가 아닌 &lt;strong&gt;weakly consistent / snapshot&lt;/strong&gt; iterator 를 쓴다.&lt;/p&gt;
&lt;h2 id=&quot;메커니즘-modcount&quot;&gt;메커니즘, modCount&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;AbstractList&lt;/code&gt;, &lt;code&gt;ArrayList&lt;/code&gt;, &lt;code&gt;LinkedList&lt;/code&gt;, &lt;code&gt;Vector&lt;/code&gt;, &lt;code&gt;HashMap&lt;/code&gt; 등은 내부에 &lt;code&gt;modCount&lt;/code&gt; 라는 정수 필드를 가진다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; abstract&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AbstractList&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AbstractCollection&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; List&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    protected&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; transient&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; modCount &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // 구조 변경 메서드마다 modCount++&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;구조 변경 (structural modification)&lt;/strong&gt; 이 일어날 때마다 &lt;code&gt;modCount++&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;iterator 생성 시 &lt;code&gt;expectedModCount = modCount&lt;/code&gt; 로 스냅샷&lt;/li&gt;
&lt;li&gt;&lt;code&gt;next()&lt;/code&gt;, &lt;code&gt;remove()&lt;/code&gt; 등 호출마다 &lt;code&gt;expectedModCount == modCount&lt;/code&gt; 검사&lt;/li&gt;
&lt;li&gt;다르면 &lt;code&gt;throw new ConcurrentModificationException()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ArrayList.Itr (단순화)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Itr&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Iterator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; cursor;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; lastRet &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; expectedModCount &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; modCount;   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ← 스냅샷&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; E &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        checkForComodification&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();      &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ← 매번 검사&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // ... return element ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; checkForComodification&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (modCount &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; expectedModCount)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ConcurrentModificationException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;구조-변경이란&quot;&gt;구조 변경이란&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;modCount&lt;/code&gt; 가 증가하는 작업은 &lt;strong&gt;컬렉션의 크기를 바꾸거나 내부 배열을 새로 할당하는&lt;/strong&gt; 작업.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;add(E)&lt;/code&gt;, &lt;code&gt;add(int, E)&lt;/code&gt;, &lt;code&gt;addAll(...)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;remove(int)&lt;/code&gt;, &lt;code&gt;remove(Object)&lt;/code&gt;, &lt;code&gt;removeAll(...)&lt;/code&gt;, &lt;code&gt;clear()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ArrayList.trimToSize()&lt;/code&gt;, &lt;code&gt;ensureCapacity(int)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LinkedHashMap&lt;/code&gt; 등의 &lt;code&gt;put()&lt;/code&gt; 으로 새 키 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;set(int, E)&lt;/code&gt; 처럼 기존 원소를 교체만 하는 작업은 구조 변경이 아니다.&lt;/strong&gt; 따라서 fail-fast 가 발생하지 않는다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;(List.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (Integer x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;99&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ✓ OK, 구조 변경 아님&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;트리거-예시&quot;&gt;트리거 예시&lt;/h2&gt;
&lt;h3 id=&quot;단일-스레드의-자기-수정&quot;&gt;단일 스레드의 자기 수정&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;(List.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (Integer x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ CME&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;순회 중 자기 자신을 수정해도 발생. &lt;strong&gt;멀티스레드만의 문제가 아니다.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;안전한-패턴&quot;&gt;안전한 패턴&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ✓ Iterator.remove() 만 fail-fast 영향 없음&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Iterator&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; it &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (it.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;hasNext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (it.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) it.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ✓ Java 8+: Collection.removeIf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;removeIf&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ✓ 복사본을 순회하면서 원본 수정&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (Integer x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;(list)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;멀티스레드에서&quot;&gt;멀티스레드에서&lt;/h2&gt;
&lt;p&gt;다른 스레드가 add/remove 하면 &lt;code&gt;modCount&lt;/code&gt; 가 증가, 내 iterator 가 다음 &lt;code&gt;next()&lt;/code&gt; 에서 CME. 단, fail-fast 는 &lt;strong&gt;best-effort 검사&lt;/strong&gt;, 절대 보장이 아니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[!CAUTION]
&lt;strong&gt;fail-fast 가 CME 를 던지지 않는다고 해서 안전한 것은 아니다.&lt;/strong&gt; &lt;code&gt;modCount&lt;/code&gt; 검사는 동기화 없이 수행되므로, 두 스레드가 동시에 수정/순회하면 &lt;code&gt;modCount&lt;/code&gt; 조차 비정상 상태로 보일 수 있다. CME 가 발생하지 않은 채 잘못된 결과 (배열 인덱스 ArrayIndexOutOfBoundsException, NullPointerException, 무한 루프) 가 나올 수 있다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;진짜 동시성 안전이 필요하면 [[CopyOnWriteArrayList]] / &lt;code&gt;ConcurrentHashMap&lt;/code&gt; 또는 외부 동기화.&lt;/p&gt;
&lt;h2 id=&quot;fail-fast-vs-weakly-consistent-vs-snapshot&quot;&gt;fail-fast vs weakly consistent vs snapshot&lt;/h2&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;종류&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;컬렉션&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;동시 수정 시 동작&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;보는 데이터&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;fail-fast&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;ArrayList, LinkedList, Vector, HashMap&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;CME 즉시 던짐 (best-effort)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;수정 전 상태&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;weakly consistent&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;ConcurrentHashMap, ConcurrentLinkedQueue&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;예외 없음, 순회 계속&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;일부 수정 반영 가능&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;snapshot&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;CopyOnWriteArrayList, CopyOnWriteArraySet&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;예외 없음, 순회 계속&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;iterator 생성 시점 (이후 수정 안 보임)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;왜-fail-fast-인가&quot;&gt;왜 fail-fast 인가&lt;/h2&gt;
&lt;p&gt;처음 보면 “왜 일부러 예외를 던지는 것이지?” 싶다. 대안 (silent corruption) 이 훨씬 무서운 디버깅 경험을 만들기 때문이다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CME 가 없다면&lt;/strong&gt;: 순회가 무한 루프, 같은 원소 두 번 방문, 잘못된 인덱스 접근 등 진단 불가능한 증상으로 나타난다. 며칠을 디버깅하다 결국 다른 스레드가 컬렉션을 건드린 것을 발견.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CME 가 있으면&lt;/strong&gt;: 즉시 스택 트레이스로 위치 파악, 수정 누가 한 것인지 추적 가능.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
CME 는 적이 아니다, 친구다. &lt;strong&gt;CME 가 발생하면 코드의 동시성 가정이 틀렸다는 신호.&lt;/strong&gt; 무시하거나 catch 해서 삼키지 말고, 동시성 컬렉션을 쓰거나 동기화를 추가하라.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[ConcurrentModificationException]]&lt;/li&gt;
&lt;li&gt;[[List]]&lt;/li&gt;
&lt;li&gt;[[ArrayList]]&lt;/li&gt;
&lt;li&gt;[[LinkedList]]&lt;/li&gt;
&lt;li&gt;[[Vector]]&lt;/li&gt;
&lt;li&gt;[[CopyOnWriteArrayList]]&lt;/li&gt;
&lt;li&gt;Joshua Bloch, &lt;em&gt;Effective Java&lt;/em&gt; (3rd ed.), Item 80 (스레드보다는 실행자, 태스크, 스트림을 애용하라)&lt;/li&gt;
&lt;li&gt;Brian Goetz, &lt;em&gt;Java Concurrency in Practice&lt;/em&gt;, §5.1.2 Iterators and ConcurrentModificationException&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>collection</category><category>iterator</category><category>concurrency</category><category>fail-fast</category><author>koa (김신건)</author></item><item><title>[Java] HashMap</title><link>https://shinkeonkim.com/wiki/java/java-hashmap/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-hashmap/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.HashMap&amp;#x3C;K,V&gt;&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;해시 테이블&lt;/strong&gt; 로 구현된 [[Map]]. 평균 O(1) 의 put/get/remove 를 보장하고 단일 스레드 환경의 사실상 표준.&lt;/p&gt;
&lt;p&gt;JDK 1.2 도입, Java 8 에서 &lt;strong&gt;충돌 시 linked list → red-black tree 로 자동 변환&lt;/strong&gt; 하는 큰 개선이 있었다.&lt;/p&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;내부-구조&quot;&gt;내부 구조&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; HashMap&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AbstractMap&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Map&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Cloneable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Serializable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    transient&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;[] table;          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 버킷 배열&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    transient&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; size;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; threshold;                         &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// capacity * loadFactor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; float&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; loadFactor;                &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 기본 0.75&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Node&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Map.Entry&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; hash;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; K key;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        V value;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; next;                    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// chaining (linked list)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;table&lt;/code&gt;&lt;/strong&gt;: 버킷 배열, 기본 길이 16, 2^n 형태로 grow&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Node&lt;/code&gt;&lt;/strong&gt;: linked list 의 노드&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java 8+&lt;/strong&gt;: 한 버킷의 노드가 &lt;strong&gt;8 개 이상&lt;/strong&gt; 이면 &lt;code&gt;TreeNode&lt;/code&gt; (red-black tree) 로 변환 → &lt;strong&gt;64 미만&lt;/strong&gt; 이면 다시 list&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;put-의-흐름&quot;&gt;put 의 흐름&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;hash = key.hashCode()&lt;/code&gt; 후 spread (상위 16비트 XOR)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;index = (table.length - 1) &amp;#x26; hash&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;버킷이 비어 있으면 → 새 Node 삽입&lt;/li&gt;
&lt;li&gt;같은 key 가 있으면 → 값 교체&lt;/li&gt;
&lt;li&gt;충돌 → linked list 끝에 append (또는 tree 에 insert)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;size &gt; threshold&lt;/code&gt; → resize (2x grow + rehash)&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; V &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(K key, V value) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; h &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; spread&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(key.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;hashCode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (table.length &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; h;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;K&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;V&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; first &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; table[i];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (first &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        table[i] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Node&amp;#x3C;&gt;(h, key, value, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // chain 순회, 같은 key 발견 시 교체&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // 끝에 도달하면 append, 8 개 이상이면 treeify&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;size &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; threshold) &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;resize&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;충돌-처리-chaining-과-treeify&quot;&gt;충돌 처리, chaining 과 treeify&lt;/h2&gt;
&lt;p&gt;같은 버킷에 여러 key 가 매핑되면 (해시 충돌):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TREEIFY_THRESHOLD = 8&lt;/strong&gt;: 한 버킷에 8 노드 이상이면 tree 로 변환 (단, table 크기가 64 이상일 때만)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UNTREEIFY_THRESHOLD = 6&lt;/strong&gt;: tree 가 6 노드 이하로 줄면 다시 list&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MIN_TREEIFY_CAPACITY = 64&lt;/strong&gt;: table 이 작을 때는 resize 가 우선&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;tree 로 변환되면 그 버킷의 최악 검색이 O(log n). 악의적 hash collision (수많은 입력이 같은 hash) 으로부터 보호.&lt;/p&gt;
&lt;h2 id=&quot;복잡도&quot;&gt;복잡도&lt;/h2&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;작업&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;평균&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;최악 (Java 8+)&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;최악 (Java 7 이전)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;get&lt;/code&gt;, &lt;code&gt;put&lt;/code&gt;, &lt;code&gt;remove&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(log n)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;containsValue&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;iterator 순회&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n + capacity)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;같음&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;같음&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;code&gt;containsKey&lt;/code&gt; 의 평균이 O(1) 인 이유는 해시 충돌이 적기 때문. 충돌이 폭주하지 않으려면 &lt;code&gt;equals&lt;/code&gt;/&lt;code&gt;hashCode&lt;/code&gt; 가 잘 분포해야 한다.&lt;/p&gt;
&lt;h2 id=&quot;load-factor-와-resize&quot;&gt;load factor 와 resize&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;loadFactor&lt;/code&gt;&lt;/strong&gt; (기본 0.75): &lt;code&gt;size / capacity&lt;/code&gt; 가 이를 초과하면 resize&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;resize()&lt;/code&gt;&lt;/strong&gt;: table 길이를 2 배로 늘리고 모든 entry 를 새 위치로 rehash. &lt;strong&gt;O(n)&lt;/strong&gt; 비용.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;생성 시 초기 capacity 지정으로 미리 줄일 수 있다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 1000 개 entry 예상 → capacity 가 1000 / 0.75 ≈ 1334 보다 커야 resize 안 함&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Map&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; map &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; HashMap&amp;#x3C;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2048&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;null-허용&quot;&gt;null 허용&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;HashMap&lt;/code&gt; 은 &lt;strong&gt;key 와 value 모두 null 허용&lt;/strong&gt;. key 가 null 이면 항상 버킷 0 에 매핑.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);              &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;a&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);            &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                 &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;[[ConcurrentHashMap]] 과의 가장 큰 차이.&lt;/p&gt;
&lt;h2 id=&quot;함정&quot;&gt;함정&lt;/h2&gt;
&lt;h3 id=&quot;1-가변-객체를-key-로-쓰면-안-됨&quot;&gt;1. 가변 객체를 key 로 쓰면 안 됨&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Map&amp;#x3C;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; map &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; HashMap&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; key &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;(List.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(key, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;v&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;key.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                      &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// hashCode 변경&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(key);                    &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// null! (다른 버킷으로 가게 됨)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;불변 객체&lt;/strong&gt; (String, Integer, Long, Enum, record) 를 key 로 사용 권장.&lt;/p&gt;
&lt;h3 id=&quot;2-equals-만-override-하고-hashcode-안-함&quot;&gt;2. equals 만 override 하고 hashCode 안 함&lt;/h3&gt;
&lt;p&gt;[[Object]] 의 규약 위반. HashMap 이 조용히 잘못 동작.&lt;/p&gt;
&lt;h3 id=&quot;3-동시-수정&quot;&gt;3. 동시 수정&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;HashMap&lt;/code&gt; 은 thread-safe 가 아니다. 동시 put 으로 &lt;strong&gt;무한 루프&lt;/strong&gt; 가 발생한 사례가 유명 (특히 Java 7 의 resize 중 chain 역전 버그). [[ConcurrentHashMap]] 사용.&lt;/p&gt;
&lt;h3 id=&quot;4-iterator-는-fail-fast-iterator&quot;&gt;4. iterator 는 [[fail-fast iterator]]&lt;/h3&gt;
&lt;p&gt;순회 중 수정 → [[ConcurrentModificationException]].&lt;/p&gt;
&lt;h2 id=&quot;hashmap-vs-hashtable-vs-concurrenthashmap&quot;&gt;HashMap vs Hashtable vs ConcurrentHashMap&lt;/h2&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;항목&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;HashMap&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;Hashtable&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;ConcurrentHashMap&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;Thread-safe&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓ (메서드)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓ (bin-level)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;null key/value&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✗&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;도입&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;JDK 1.2&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;JDK 1.0 (legacy)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;JDK 1.5&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;성능&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;가장 빠름&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;느림 (전체 락)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;동시성 최적&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;권장&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;단일 스레드&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;절대 X&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;동시성&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[Object]]&lt;/li&gt;
&lt;li&gt;[[Iterable]]&lt;/li&gt;
&lt;li&gt;[[Collection]]&lt;/li&gt;
&lt;li&gt;[[Map]]&lt;/li&gt;
&lt;li&gt;[[LinkedHashMap]]&lt;/li&gt;
&lt;li&gt;[[TreeMap]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentHashMap]]&lt;/li&gt;
&lt;li&gt;[[Spring] ConcurrentReferenceHashMap]]&lt;/li&gt;
&lt;li&gt;[[fail-fast iterator]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentModificationException]]&lt;/li&gt;
&lt;li&gt;Joshua Bloch, &lt;em&gt;Effective Java&lt;/em&gt; (3rd ed.), Items 10-11 (equals, hashCode)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>collection</category><category>map</category><category>hash</category><category>jcf</category><author>koa (김신건)</author></item><item><title>[Java] HashSet</title><link>https://shinkeonkim.com/wiki/java/java-hashset/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-hashset/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.HashSet&amp;#x3C;E&gt;&lt;/code&gt;&lt;/strong&gt; 는 [[HashMap]] 을 백킹으로 사용하는 [[Set]] 구현. 내부적으로 모든 원소를 HashMap 의 key 로 저장하고, value 는 dummy 상수 &lt;code&gt;PRESENT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;평균 O(1) 의 add/remove/contains. 순서는 보장되지 않는다. 가장 흔한 Set 구현.&lt;/p&gt;
&lt;h2 id=&quot;내부-구조&quot;&gt;내부 구조&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; HashSet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AbstractSet&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Set&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt;, ... {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; transient&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; HashMap&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Object&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; map;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; static&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Object PRESENT &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Object&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(E &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(e, PRESENT) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; contains&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Object &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;o&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; map.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;containsKey&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(o);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;    // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;HashMap&lt;/code&gt; 의 모든 동작과 성능 특성을 그대로 물려받는다. capacity/loadFactor, treeify 같은 내용은 [[HashMap]] 참고.&lt;/p&gt;
&lt;h2 id=&quot;복잡도&quot;&gt;복잡도&lt;/h2&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;작업&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;평균&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;최악 (Java 8+)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;add&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(log n)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;contains&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(log n)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;remove&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(log n)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;순회&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(n + capacity)&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;같음&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;null-허용&quot;&gt;null 허용&lt;/h2&gt;
&lt;p&gt;원소 하나는 null 가능 (HashMap 의 null key 처럼).&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Set&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; s &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; HashSet&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;s.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                     &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;s.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                     &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// false (이미 있음)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;s.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;contains&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;null&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);                &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Set.of(null)&lt;/code&gt; 은 NPE.&lt;/p&gt;
&lt;h2 id=&quot;함정&quot;&gt;함정&lt;/h2&gt;
&lt;p&gt;[[HashMap]] 의 함정이 그대로 적용.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;가변 객체 사용 금지&lt;/li&gt;
&lt;li&gt;&lt;code&gt;equals&lt;/code&gt; / &lt;code&gt;hashCode&lt;/code&gt; 규약 준수&lt;/li&gt;
&lt;li&gt;thread-safe 가 아님 → 동시성 필요 시 &lt;code&gt;Collections.synchronizedSet&lt;/code&gt; 또는 &lt;code&gt;ConcurrentHashMap.newKeySet()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;iterator 는 [[fail-fast iterator]]&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[Object]]&lt;/li&gt;
&lt;li&gt;[[Iterable]]&lt;/li&gt;
&lt;li&gt;[[Collection]]&lt;/li&gt;
&lt;li&gt;[[Set]]&lt;/li&gt;
&lt;li&gt;[[Map]]&lt;/li&gt;
&lt;li&gt;[[HashMap]]&lt;/li&gt;
&lt;li&gt;[[TreeSet]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentHashMap]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>collection</category><category>set</category><category>hash</category><author>koa (김신건)</author></item><item><title>[Java] Iterable</title><link>https://shinkeonkim.com/wiki/java/java-iterable/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-iterable/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.lang.Iterable&amp;#x3C;T&gt;&lt;/code&gt;&lt;/strong&gt; 는 &lt;strong&gt;&lt;code&gt;for-each&lt;/code&gt; 루프로 순회 가능한 모든 타입의 최상위 인터페이스&lt;/strong&gt;. 단 하나의 추상 메서드, &lt;code&gt;iterator()&lt;/code&gt; 를 정의한다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Iterable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    Iterator&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    default&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; forEach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Consumer&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; super&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;action&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { ... }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    default&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Spliterator&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;spliterator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { ... }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;[[Collection]] 인터페이스가 &lt;code&gt;Iterable&lt;/code&gt; 을 extends 하므로 [[ArrayList]], [[LinkedList]], &lt;code&gt;HashSet&lt;/code&gt;, &lt;code&gt;LinkedList&lt;/code&gt; 등 모든 컬렉션이 자동으로 &lt;code&gt;for-each&lt;/code&gt; 대상이 된다. &lt;strong&gt;컬렉션이 아닌 사용자 정의 타입&lt;/strong&gt; 도 &lt;code&gt;Iterable&lt;/code&gt; 만 구현하면 같은 문법으로 순회 가능.&lt;/p&gt;
&lt;h2 id=&quot;for-each-문의-desugaring&quot;&gt;for-each 문의 desugaring&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (String s &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; myIterable) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(s);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 코드는 컴파일 시 아래로 변환된다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Iterator&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; $it &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; myIterable.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ($it.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;hasNext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    String s &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; $it.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(s);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;즉 &lt;code&gt;for-each&lt;/code&gt; 는 &lt;strong&gt;단순히 &lt;code&gt;iterator()&lt;/code&gt; 호출 + &lt;code&gt;hasNext()&lt;/code&gt; / &lt;code&gt;next()&lt;/code&gt; 패턴의 문법 설탕&lt;/strong&gt;. 배열의 경우는 컴파일러가 인덱스 기반 &lt;code&gt;for&lt;/code&gt; 로 변환 (배열은 &lt;code&gt;Iterable&lt;/code&gt; 이 아님, 특별 케이스).&lt;/p&gt;
&lt;h2 id=&quot;iterator-인터페이스&quot;&gt;Iterator 인터페이스&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Iterable.iterator()&lt;/code&gt; 가 반환하는 객체는 &lt;code&gt;Iterator&amp;#x3C;E&gt;&lt;/code&gt; 를 구현해야 한다.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Iterator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    boolean&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; hasNext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();         &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 다음 원소가 있는가&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    E &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 다음 원소를 반환, 커서 전진&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    default&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; remove&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { ... }  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 마지막에 반환한 원소를 삭제 (선택)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    default&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; forEachRemaining&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(Consumer&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; super&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;action&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { ... }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3가지 약속:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;hasNext()&lt;/code&gt; 가 true 인 동안에만 &lt;code&gt;next()&lt;/code&gt; 호출 가능&lt;/strong&gt;, 아니면 &lt;code&gt;NoSuchElementException&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;remove()&lt;/code&gt; 는 직전 &lt;code&gt;next()&lt;/code&gt; 호출이 있어야&lt;/strong&gt; 호출 가능, 아니면 &lt;code&gt;IllegalStateException&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;remove()&lt;/code&gt; 두 번 연속 호출 금지&lt;/strong&gt;, 다음 &lt;code&gt;next()&lt;/code&gt; 가 있어야 다시 가능&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;사용자-정의-iterable&quot;&gt;사용자 정의 Iterable&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Iterable&lt;/code&gt; 구현은 매우 간단하다. 예: 1 부터 N 까지 정수를 순회하는 타입.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Range&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Iterable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; end;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Range&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt; end&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;this&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.end &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; end; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Iterator&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Iterator&amp;#x3C;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; hasNext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;#x3C;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; end; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Integer &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;hasNext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; NoSuchElementException&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 사용&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Range&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x);   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 1, 2, 3, 4, 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;기본-메서드-두-가지&quot;&gt;기본 메서드 두 가지&lt;/h2&gt;
&lt;h3 id=&quot;foreachconsumer&quot;&gt;&lt;code&gt;forEach(Consumer)&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Java 8 부터 추가. 람다와 함께 더 간결.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(System.out&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;println);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; log.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;info&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;item: {}&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, x));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;내부적으로 &lt;code&gt;iterator()&lt;/code&gt; 사용. 따라서 [[fail-fast iterator]] 의 영향을 받는다 (수정 중이면 CME).&lt;/p&gt;
&lt;h3 id=&quot;spliterator&quot;&gt;&lt;code&gt;spliterator()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Java 8 부터 추가. Stream / 병렬 처리를 위해 컬렉션을 분할 가능한 형태로 노출.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;spliterator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();          &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 단일 spliterator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stream&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();               &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// Stream API 의 입구&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;parallelStream&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();       &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 병렬 Stream&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;대부분의 사용자가 직접 &lt;code&gt;spliterator()&lt;/code&gt; 를 호출할 일은 없다. Stream API 가 알아서 사용.&lt;/p&gt;
&lt;h2 id=&quot;iterable-vs-collection-vs-stream&quot;&gt;Iterable vs Collection vs Stream&lt;/h2&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;Iterable&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;Collection&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;Stream&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;크기 알 수 있나&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;보장 안 됨&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;size()&lt;/code&gt; 있음&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;보장 안 됨&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;재사용 가능한가&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✓ (여러 번 iterator 생성 가능)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✗ (1회 소비)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;수정 가능한가&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;정의 안 함&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;add/remove 정의&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✗ (불변 파이프라인)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;무한 가능한가&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✓&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✗&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;✓&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;상위 관계&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;최상위&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;extends Iterable&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;별도 인터페이스&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;[!IMPORTANT]
&lt;strong&gt;&lt;code&gt;Iterable&lt;/code&gt; 은 크기와 무한성에 대한 약속이 없다.&lt;/strong&gt; 무한 시퀀스를 &lt;code&gt;Iterable&lt;/code&gt; 로 모델링해도 합법. 다만 &lt;code&gt;for-each&lt;/code&gt; 가 영원히 안 끝나니 break 가 필요. 대안으로 &lt;code&gt;Stream&lt;/code&gt; 의 &lt;code&gt;limit(n)&lt;/code&gt; / &lt;code&gt;takeWhile&lt;/code&gt; 이 더 명확.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;무한-iterable-의-예&quot;&gt;무한 Iterable 의 예&lt;/h2&gt;
&lt;p&gt;피보나치 수열을 무한 시퀀스로:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Fibonacci&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Iterable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Iterator&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Iterator&amp;#x3C;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; a &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, b &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; boolean&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; hasNext&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;; }  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 무한&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Long &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; r &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; a;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; next &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; a &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; b;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                a &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; b; b &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; next;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;                return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; r;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 사용&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;long&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Fibonacci&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;break&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    System.out.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Iterable&lt;/code&gt; 의 강점은 이런 lazy / 무한 시퀀스도 자연스럽게 표현되는 점.&lt;/p&gt;
&lt;h2 id=&quot;stream-으로-변환&quot;&gt;Stream 으로 변환&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Iterable&lt;/code&gt; 을 &lt;code&gt;Stream&lt;/code&gt; 으로 바꾸는 표준 방법:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Iterable&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; it &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ...;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Stream&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;String&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; stream &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; StreamSupport.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;stream&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(it.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;spliterator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(), &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;false&lt;/code&gt; 는 순차 스트림, &lt;code&gt;true&lt;/code&gt; 는 병렬. Iterable 이 spliterator() 의 기본 구현을 갖고 있어 가능.&lt;/p&gt;
&lt;h2 id=&quot;자주-만나는-함정&quot;&gt;자주 만나는 함정&lt;/h2&gt;
&lt;h3 id=&quot;1-iterator-가-매번-새-인스턴스를-반환해야-함&quot;&gt;1. iterator() 가 매번 새 인스턴스를 반환해야 함&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ 잘못된 구현 - iterator 를 캐시&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; BadIterable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;implements&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Iterable&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Iterator&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; it;  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 단 하나 보관&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Override&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Iterator&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() { &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; it; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// → for-each 두 번 돌리면 두 번째에서 hasNext() == false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;매 &lt;code&gt;iterator()&lt;/code&gt; 호출이 새 인스턴스를 반환해야 다회 순회가 가능.&lt;/p&gt;
&lt;h3 id=&quot;2-for-each-안에서-수정--cme&quot;&gt;2. &lt;code&gt;for-each&lt;/code&gt; 안에서 수정 → CME&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ArrayList&amp;#x3C;&gt;(List.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;of&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (Integer x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// ❌ ConcurrentModificationException&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;[[ConcurrentModificationException]] 참조.&lt;/p&gt;
&lt;h3 id=&quot;3-next-의-결과를-두-번-부르면-두-원소가-진행됨&quot;&gt;3. &lt;code&gt;next()&lt;/code&gt; 의 결과를 두 번 부르면 두 원소가 진행됨&lt;/h3&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Iterator&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; it &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (it.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; it.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) { ... }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;//   ^^^^^^^^^^      ^^^^^^^^^^&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;//   첫 원소         두 번째 원소 (의도와 다를 수 있음)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;it.next()&lt;/code&gt; 는 부수효과 (커서 전진) 가 있다. 한 번만 부르고 변수에 저장하라.&lt;/p&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[Object]]&lt;/li&gt;
&lt;li&gt;[[Collection]]&lt;/li&gt;
&lt;li&gt;[[List]]&lt;/li&gt;
&lt;li&gt;[[fail-fast iterator]]&lt;/li&gt;
&lt;li&gt;[[ConcurrentModificationException]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>fundamentals</category><category>iterator</category><category>collection</category><category>interface</category><author>koa (김신건)</author></item><item><title>[Java] LinkedBlockingQueue</title><link>https://shinkeonkim.com/wiki/java/java-linkedblockingqueue/</link><guid isPermaLink="true">https://shinkeonkim.com/wiki/java/java-linkedblockingqueue/</guid><pubDate>Thu, 18 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;정의&quot;&gt;정의&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;java.util.concurrent.LinkedBlockingQueue&amp;#x3C;E&gt;&lt;/code&gt;&lt;/strong&gt; 는 linked list 기반의 [[BlockingQueue]]. 기본 unbounded (&lt;code&gt;Integer.MAX_VALUE&lt;/code&gt;) 이지만 생성 시 capacity 지정 가능.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Two-Lock Queue 알고리즘&lt;/strong&gt; 으로 producer 와 consumer 가 &lt;strong&gt;서로 다른 락&lt;/strong&gt; 을 사용 → ArrayBlockingQueue 보다 높은 throughput.&lt;/p&gt;
&lt;h2 id=&quot;시각화&quot;&gt;시각화&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;내부-구조&quot;&gt;내부 구조&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; LinkedBlockingQueue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; ... {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; capacity;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; AtomicInteger count &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; AtomicInteger&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    transient&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; head;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; transient&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Node&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;E&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; last;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ReentrantLock takeLock &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ReentrantLock&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Condition notEmpty &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; takeLock.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;newCondition&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ReentrantLock putLock &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; ReentrantLock&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    private&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; final&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Condition notFull &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; putLock.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;newCondition&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;핵심: &lt;strong&gt;takeLock 과 putLock 이 분리&lt;/strong&gt;. take 와 put 이 동시에 진행 가능 (다른 끝을 다루므로).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;count&lt;/code&gt; 는 &lt;code&gt;AtomicInteger&lt;/code&gt;, 두 락 모두에서 안전하게 갱신.&lt;/p&gt;
&lt;h2 id=&quot;두-락의-협력&quot;&gt;두 락의 협력&lt;/h2&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; void&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; put&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(E e) throws InterruptedException {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    putLock.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;lockInterruptibly&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (count.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; capacity) notFull.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        enqueue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; Node&amp;#x3C;&gt;(e));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; c &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; count.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getAndIncrement&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (c &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; capacity) notFull.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;signal&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 다음 put 대기자 깨움 (선택적)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { putLock.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unlock&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (c &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;signalNotEmpty&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();                  &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// take 대기자 깨움 (락 풀고)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;public&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; E &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;take&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() throws InterruptedException {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    takeLock.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;lockInterruptibly&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        while&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (count.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) notEmpty.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        E e &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; dequeue&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        int&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; c &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; count.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getAndDecrement&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (c &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) notEmpty.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;signal&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { takeLock.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;unlock&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(); }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (c &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;==&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; capacity) &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;signalNotFull&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;복잡도-및-동시성&quot;&gt;복잡도 및 동시성&lt;/h2&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;작업&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;시간&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;동시성&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;put&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;putLock 직렬&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;take&lt;/code&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;takeLock 직렬&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;code&gt;put&lt;/code&gt; ↔ &lt;code&gt;take&lt;/code&gt; 동시&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;O(1)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;병렬&lt;/strong&gt; (다른 락)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;함정&quot;&gt;함정&lt;/h2&gt;
&lt;h3 id=&quot;1-unbounded-가-기본&quot;&gt;1. unbounded 가 기본&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;new LinkedBlockingQueue&amp;#x3C;&gt;()&lt;/code&gt; 는 &lt;code&gt;Integer.MAX_VALUE&lt;/code&gt; 크기. producer 가 빠르면 OOM. &lt;strong&gt;반드시 bounded&lt;/strong&gt; 지정.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;BlockingQueue&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;Task&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;&gt; q &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; LinkedBlockingQueue&amp;#x3C;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;1000&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);   &lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// 권장&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-노드-객체-gc-압력&quot;&gt;2. 노드 객체 GC 압력&lt;/h3&gt;
&lt;p&gt;각 원소가 노드 객체로 감싸진다. 짧은 시간에 수만 개가 들어왔다 나가는 워크로드에서는 GC 영향이 보일 수 있다.&lt;/p&gt;
&lt;h2 id=&quot;linkedblockingqueue-vs-arrayblockingqueue&quot;&gt;LinkedBlockingQueue vs ArrayBlockingQueue&lt;/h2&gt;
&lt;p&gt;[[ArrayBlockingQueue]] 의 비교 표 참고. 결론적으로 high throughput 이 필요하면 LinkedBlockingQueue, 메모리 예측이 중요하면 ArrayBlockingQueue.&lt;/p&gt;
&lt;h2 id=&quot;참고&quot;&gt;참고&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[[BlockingQueue]]&lt;/li&gt;
&lt;li&gt;[[ArrayBlockingQueue]]&lt;/li&gt;
&lt;li&gt;[[ReentrantLock]]&lt;/li&gt;
&lt;li&gt;[[Blocking]]&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>java</category><category>concurrent</category><category>queue</category><category>blocking</category><category>linked-list</category><author>koa (김신건)</author></item></channel></rss>