<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>공부하고 기록하고 반복하자</title>
    <link>https://suco.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sun, 26 Jul 2026 19:57:30 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>슈코</managingEditor>
    <item>
      <title>영화 '히든피겨스'를 보고</title>
      <link>https://suco.tistory.com/100</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 주말에 대학동기의 결혼식이 있었다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;금요일에 전주를 가서 일요일에 올 수 있었지만 얼마전 몸살이 찾아와서 이번엔 휴식을 취하기로 했다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트레스가 많아졌나? 몸도 마음도 힘든 요즘이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;토요일엔 늦잠을 자기도 다짐하고, 금요일엔 영화를 한편 보기로 했다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(실제로 토요일엔 일찍 눈이 떠졌지만, 11시까지 다시 잠을 청하였다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;히든피겨스&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 영화에 흥미를 느꼈던건 유튜브에서 우연하게 보게 된 쇼츠였다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;모두가 바쁜거 같은 사무실에서 화장실에 다녀온 흑인 여성&lt;br /&gt;책임자는 어딜 다녀오냐고 윽박을 지른다&lt;br /&gt;여성은 800m 떨어진 흑인 전용 화장실을 다녀오느라 늦었다고 소리친다&lt;br /&gt;짧은 영상에 그녀의 그동안의 울분이 모두 쏟아지는거 같았다&lt;br /&gt;책임자는 그 소리를 듣고 곧장 해머로 백인 전용 화장실 간판을 부셔버린다&lt;br /&gt;나사에는 화장실 구분이 없다는 말과 함께&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 짧은 영상을 보고 흥미가 생겼다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 나는 아시아인을 차별하는 내용을 인터넷으로 종종 접했지만, 흑인에 대한 차별은 제대로 알지 못했다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생기지 않는 동기부여를 부여잡고 싶은 마음이 이끌었는지도 모른다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영화는 제목 그대로 숨겨진 영웅들을 다룬다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나사에서 우주 탐험을 위해서 노력했던 그 많은 사람들중 내가 전혀 몰랐던 분들이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영화에 나오는 주인공들은 세명의 흑인 여성들인데 한명 한명 차별을 느끼고 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한명은 엔지니어를 꿈꾸는데, 성적은 우수하지만 백인들만 다닐 수 있는 학교에 수업을 들어야하는 조건이 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(지금 생각하면 정말 말도 안되는 건데, 우리나라 조선시대만 생각해도 너무 당연한것들이 많았으니...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 한명은 관리자 직책을 맡기지도 않으면서 관리자처럼 일을 시킨다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나사에는 IBM이 도입되려고 하면서 단순 계산을 하고 있는 계산원들은 위기의식을 느끼기도 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 한명은 탁월한 계산 능력을 가지고 있는데 상사의 무시를 기본적으로 느끼고, 본인은 참석할 수 없는 회의에서 위치가 자꾸 바뀌면서 쓸데없는 계산을 여러번 반복하는 일도 생긴다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, 기본적으로 가장 놀라웠던건 백인 전용 화장실, 흑인용 화장실이 따로 있고 커피포트도 같이 쓰는걸 꺼려하는 그 분위기다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흑인용 화장실에 'colored'가 붙어있는데 생각해보니...흰색은 색이 없는거고 흑색은 색이 있는거라 그런거구나...놀랍다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 말도 안되는 상황속에서도 주인공들은 포기하지 않는다. 모든 영화가 마지막에 해피엔딩으로 끝나는 경우가 많아서 그걸 예상했지만, 특히나 이 영화 엔딩에서 주인공들의 행복한 모습이 너무 보고싶어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔지니어를 꿈꾸던 주인공은 판사를 설득하여 수업을 들을 수 있었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관리자를 꿈꾸던 주인공은 미래(IBM으로 계산)를 먼저 보고 포트란 언어를 공부하여 프로그래머?로 전향?한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 위기속에서도 공부하여 멋지게 기계를 활용하는 모습을 보고 감탄을 금치 못했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 계산을 잘하는 주인공은 IBM의 치명적인 실수를 계산을 통하여 바로잡아 우주 계획을 성공적으로 이끌었다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계산원(계산을 담당하는 직원)들을 보면서는 지금 개발자들이 생각났다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 계산을 사람이 하다가, 컴퓨터가 계산을 하게되면 그 차이는 정말 감당할 수 없었을 것 이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IBM에 쫓겨 일자리를 잃을 수 있었지만, 역으로 IBM을 다룰 준비를 하다니!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대 AI 시대가 도래하면서, AI에게 일자리를 뺏기고 개발자를 못하게 되는건 아닌가? 하는 불안한 개발자들에게 이 영화를 보여주고 싶었다. 그리고, 정말 저렇게 말도 안되는 차별속에서도 꿈을 위해 노력을 포기하지 않고 결국 이루어 내는 주인공들을 보면서 내가 느꼈던 그 사소한 불합리한 것들은 정말 얼마나 나 스스로가 바보같은지를 생각해보게 되었다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사도 이런저런 이슈로 시끌벅적한 요즘인데, 다시 한번 생각해보자&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;나는 화장실에 가려고 800m를 가지 않는다&lt;/li&gt;
&lt;li&gt;나는 물도 자유롭게 마실 수 있다&lt;/li&gt;
&lt;li&gt;나는 책 한권 빌리는게 몰래 가져오듯이 힘들지 않는다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AI 시대라 불안한가? 공부하는데 막는 사람은 아무도 없다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>생각정리</category>
      <author>슈코</author>
      <guid isPermaLink="true">https://suco.tistory.com/100</guid>
      <comments>https://suco.tistory.com/100#entry100comment</comments>
      <pubDate>Sun, 28 Sep 2025 22:56:11 +0900</pubDate>
    </item>
    <item>
      <title>질문이 너무 많으면</title>
      <link>https://suco.tistory.com/84</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;질문이 너무 많은 사람을 만나서 귀찮거나 혹은 짜증이 난다면?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 사람이 질문 안해도 되는 환경을 만든다!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 오늘도 배운다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계속 질문을 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 개선할점이 있는건가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 혼자 개발할 수 있는 충분한 환경을 만드는게 중요하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 고민거리같은거 말고 일을 하는데 있어서 필요한 질문들&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 문서화가 잘 안되어 있나?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹은 그 문서를 찾는데 너무 어렵게 되어있나?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;등을 고려하는 것 이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘도 배운다!!&lt;/p&gt;</description>
      <category>생각정리</category>
      <author>슈코</author>
      <guid isPermaLink="true">https://suco.tistory.com/84</guid>
      <comments>https://suco.tistory.com/84#entry84comment</comments>
      <pubDate>Tue, 6 May 2025 10:04:08 +0900</pubDate>
    </item>
    <item>
      <title>가을아침</title>
      <link>https://suco.tistory.com/69</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;혹독한 무더위가 지나가고 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;30일 넘는 열대야를 경험했고, 에어컨없이 살기 힘든 주말의 연속이었다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회사는 쾌적하였지만, 회사까지 가는것 조차 힘든 여름이랄까...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 끝나지 않을것만 같았던 이 여름도 조금씩 헤어질 준비를 하는거 같다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아침에 집을 나오는데, 이제 그렇게 덥다는 느낌이 없다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 물론 한낮에는 여전히 덥지만 말이다... )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오히려 조금 선선한 바람이 부는날이면 가을이 오고 있음을 실감한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가을에는 가을아침이지!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 아침 출근길에 바로 선곡하였다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘 회사 분위기가 많이 좋지 않고 일이 많아서 힘든 시기이지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 큰 무더위로 힘든 여름이 지나가듯 이 시기도 지나갈거라고 믿는다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꾸준히 공부하면서 가을을 맞이하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>생각정리</category>
      <author>슈코</author>
      <guid isPermaLink="true">https://suco.tistory.com/69</guid>
      <comments>https://suco.tistory.com/69#entry69comment</comments>
      <pubDate>Wed, 4 Sep 2024 07:35:32 +0900</pubDate>
    </item>
    <item>
      <title>스레드 - interrupt()</title>
      <link>https://suco.tistory.com/68</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;스레드의 작업을 중간에 중단하는 방법&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;flag값 설정 및 수정&lt;/li&gt;
&lt;li&gt;interrupt() 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;flag값 설정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 스레드의 실행을 flag 값이 true인 동안 계속해서 작업하도록 설정한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 스레드를 중단하는 시점에 flag 값을 false로 바꾼다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면, 다음 반복문 실행 시점에 flag 값을 확인하고 해당 작업을 빠져 나온다&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;static class MyTask implements Runnable {

    volatile boolean runFlag = true;

    @Override
    public void run() {
        while (runFlag) {
            log(&quot;작업 중&quot;);
            sleep(3000);
        }
        log(&quot;자원 정리&quot;);
        log(&quot;작업 종료&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;span style=&quot;color: #ffffff;&quot;&gt;runFlag 값을 true로 설정하고, 작업을 진행하는 스레드&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    MyTask task = new MyTask();
    Thread thread = new Thread(task, &quot;work&quot;);
    thread.start();

    sleep(4000);
    log(&quot;작업 중단 지시 runFlag=false&quot;);
    task.runFlag = false;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;span style=&quot;color: #ffffff;&quot;&gt;Mytask를 실행하고, 4초 후에 해당 스레드의 상태를 false로 수정한다&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 방식을 활용하면 간단히 스레드의 작업을 중단 시킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, flag가 false로 바뀌는 시점에 &lt;b&gt;&lt;i&gt;그 시점의 반복문에서 실행하고 있는 코드는 모두 수행하고&lt;/i&gt;&lt;/b&gt;,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 조건 체크 시 빠져 나오게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;interrupt()&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터럽트는 WATING, TIMED_WAITING과 같은 대기 상태의 스레드를 깨우고, RUNNABLE 상태로 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;인터럽트 관련 메소드&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;thread.interrupt() - 해당 스레드에게 인터럽트를 건다&lt;/li&gt;
&lt;li&gt;Thread.currentThread().isInterrupted() - 해당 스레드의 상태가 인터럽트인지 체크( 인터럽트 상태 변경 x )&lt;/li&gt;
&lt;li&gt;Thread.interrupted() - 스레드의 상태가 인터럽트가 걸렸으면 true를 반환하고, 인터럽트의 상태를 변경해준다( true &amp;gt; false )&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상당히 재미있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;interrupt()는 해당 스레드에게 인터럽트를 걸어준다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터럽트를 건다고 하더라도, 즉각적으로 반응하지는 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 해당 스레드에게 &lt;b&gt;&lt;i&gt;인터럽트가 걸리는 상황이 발생할때&lt;/i&gt;&lt;/b&gt;( 예시에서는 Sleep() ) 인터럽트가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;인터럽트가 걸리면 InterruptedException이 발생하게되고, 인터럽트 상태가 해제&lt;/b&gt;&lt;/i&gt;된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    MyTask task = new MyTask();
    Thread thread = new Thread(task, &quot;work&quot;);
    thread.start();

    sleep(4000);
    log(&quot;작업 중단 지시 thread.interrupt()&quot;);
    thread.interrupt();
    log(&quot;work 스레드 인터럽트 상태1 = &quot; + thread.isInterrupted()) ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;&amp;nbsp;thread.interrupt()를 통해서 thread 에게 인터럽트를 걸어준다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;static class MyTask implements Runnable {

    volatile boolean runFlag = true;

    @Override
    public void run() {
        try {
            while (true) {
                log(&quot;작업 중&quot;);
                Thread.sleep(3000);
            }
        } catch (InterruptedException e) {
            log(&quot;work 스레드 인터럽트 상태2 = &quot; + Thread.currentThread().isInterrupted());
            log(&quot;interrupt message = &quot; + e.getMessage());
            log(&quot;state = &quot; + Thread.currentThread().getState());
        }

        log(&quot;자원 정리&quot;);
        log(&quot;작업 종료&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;&amp;nbsp;해당 스레드는 작업을 이어가다가 sleep(3000) 을 만나면, 인터럽트가 걸린다(걸리면서 해제된다)&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;isInterrupted()는 현재 스레드의 인터럽트 상태만을 체크한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 인터럽트가 걸렸다고해서 해제되는 상황이 발생하지 않는다. 그냥 체크만 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IVF9T/btsJpLFf3BL/LBLGiZGjDQTcfa18816BG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IVF9T/btsJpLFf3BL/LBLGiZGjDQTcfa18816BG1/img.png&quot; data-alt=&quot;결과값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IVF9T/btsJpLFf3BL/LBLGiZGjDQTcfa18816BG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIVF9T%2FbtsJpLFf3BL%2FLBLGiZGjDQTcfa18816BG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;514&quot; height=&quot;202&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;202&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;결과값&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업중 interrupt()가 요청되고 main에서 바로 확인한 현재 인터럽트 상태는 true가 반환된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후에 곧바로 sleep 상태에 있는 스레드에게 인터럽트가 걸리게 되고 InterruptedException을 만나면서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터럽트 상태는 false가 된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( sleep 상태가 아니고 처리하는 로직이 있었으면, 로직을 수행한다 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;interrupted()는 현재 스레드의 상태가 인터럽트 상태라면, true 반환 후에 인터럽트 상태를 변경해준다( true &amp;gt; false )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;static class MyTask implements Runnable {

    @Override
    public void run() {
        while (!Thread.interrupted()) { // 인터럽트 상태 변경X
            log(&quot;작업 중&quot;);
        }
        log(&quot;work 스레드 인터럽트 상태2 = &quot; + Thread.currentThread().isInterrupted());

        try {
            log(&quot;자원 정리&quot;);
            Thread.sleep(500);
            log(&quot;작업 종료&quot;);
        } catch (InterruptedException e) {
            log(&quot;자원 정리 실패 - 자원 정리 중 인터럽트 발생 &quot;);
            log(&quot;work 스레드 인터럽트 상태2 = &quot; + Thread.currentThread().isInterrupted());
        }


    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;&amp;nbsp;while문의 조건을 수정하였다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;기존에는 true로 주어서 무한반복이 되게끔하고, sleep 상태일때 인터럽트에 걸리면서 빠져나왔다면,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;현재는 Thread.interrupted() 메소드를 통해서 인터럽트가 걸리게 되면 바로 해당 반복문을 빠져나온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;interrupted() 메소드는 인터럽트 상태일때, true를 반환하고 그 상태값을 변경해준다&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;217&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lvJ1h/btsJo28PKwD/SNpxUf0PXcqwrHNS4Byvi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lvJ1h/btsJo28PKwD/SNpxUf0PXcqwrHNS4Byvi0/img.png&quot; data-alt=&quot;Thread.interrupted() 메소드 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lvJ1h/btsJo28PKwD/SNpxUf0PXcqwrHNS4Byvi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlvJ1h%2FbtsJo28PKwD%2FSNpxUf0PXcqwrHNS4Byvi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;464&quot; height=&quot;217&quot; data-origin-width=&quot;464&quot; data-origin-height=&quot;217&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Thread.interrupted() 메소드 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;interrupt()를 요청한 직후 main에서 확인한 인터럽트 상태는 true이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;곧바로 스레드의 &lt;i&gt;&lt;b&gt;Thread.interrupted()&lt;/b&gt;&lt;/i&gt;가 상태값을 변경하면서 &lt;b&gt;&lt;i&gt;반복문을 빠져나오고 상태는 false&lt;/i&gt;&lt;/b&gt;가 된다;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태값을 변경했기 때문에, 자원정리중 sleep()이 발생하여도 InterruptException 에 걸리지 않는다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, Thread.interrupted()를 사용하지 않고 &lt;b&gt;&lt;i&gt;Thread.currentThread.isInterrupted()&lt;/i&gt;&lt;/b&gt; 메소드를 사용하여 반복문을 빠져나오면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;반복문을 빠져나오며 상태값을 변경하지 않기때문에&lt;/b&gt;&lt;/i&gt;, 자원정리의 sleep에서 인터럽트가 발생하여 Exception이 발생하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;어떤것이 무조건 좋다고 할 순 없다&lt;br /&gt;상황에 맞게 설정해야할거 같다&lt;br /&gt;interrupt() / isInterrupted() / interrupted() 의 역할이 무엇인지 확실하게 기억하고 넘어가자&lt;br /&gt;이름이...살짝 헷갈리긴 하다...ㅎㅎ&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;interrupted()와 isInterrupted()&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한가지 궁금점이 생겼다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;isInterrupted()&lt;/b&gt;는 &lt;b&gt;Thread.currentThread&lt;/b&gt;에서 호출하는데, &lt;b&gt;&lt;i&gt;interrupted()&lt;/i&gt;&lt;/b&gt;는 &lt;i&gt;&lt;b&gt;Thread&lt;/b&gt;&lt;/i&gt;에서 호출하는 점이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 혹시 다른스레드에서 interrupt를 호출해도 Thread.interrupted()에서 걸리게 되는걸까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class ThreadTest {

    public static void main(String[] args) {
        MyTask task = new MyTask();
        Thread thread = new Thread(task, &quot;work&quot;);

        MyTask2 task2 = new MyTask2();
        Thread thread2 = new Thread(task2, &quot;work2&quot;);

        thread.start();
        thread2.start();

        sleep(500);
        log(&quot;작업 중단 지시 thread2.interrupt()&quot;);
        thread2.interrupt();
        log(&quot;work 스레드 인터럽트 상태1 = &quot; + thread.isInterrupted()) ;
        log(&quot;work 스레드2 인터럽트 상태1 = &quot; + thread2.isInterrupted()) ;
    }

    static class MyTask implements Runnable {

        @Override
        public void run() {
            while (!Thread.interrupted()) { // 인터럽트 상태 변경X
                log(&quot;작업 중&quot;);
                sleep(2000);
            }
            log(&quot;work 스레드 인터럽트 상태2 = &quot; + Thread.currentThread().isInterrupted());

            try {
                log(&quot;자원 정리&quot;);
                Thread.sleep(2000);
                log(&quot;작업 종료&quot;);
            } catch (InterruptedException e) {
                log(&quot;자원 정리 실패 - 자원 정리 중 인터럽트 발생 &quot;);
                log(&quot;work 스레드 인터럽트 상태2 = &quot; + Thread.currentThread().isInterrupted());
            }


        }
    }

    static class MyTask2 implements Runnable {

        volatile boolean runFlag = true;

        @Override
        public void run() {
            try {
                while (runFlag) {
                    log(&quot;작업 중&quot;);
                    Thread.sleep(2000);
                }
            } catch (InterruptedException e) {
                log(&quot;work2 인터럽트!&quot;);
            }

            log(&quot;자원 정리&quot;);
            log(&quot;작업 종료&quot;);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;&amp;nbsp;( 테스트용으로 한번에 코드를 올려보았다 )&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;각각 다른 스레드를 생성한다(MyTask, MyTask2)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;MyTask는 interrupted()를 사용하여 인터럽트가 걸리면 바로 빠져 나오도록 설정하고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;MyTask2는 sleep 상태일때 인터럽트가 걸리도록 설정해두었다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ffffff;&quot;&gt;main에서는 thread2(MyTask2)에게 인터럽트를 걸었다&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLiLJ6/btsJqYKf61g/53ojB02CYQMkLQxqKEj9kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLiLJ6/btsJqYKf61g/53ojB02CYQMkLQxqKEj9kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLiLJ6/btsJqYKf61g/53ojB02CYQMkLQxqKEj9kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLiLJ6%2FbtsJqYKf61g%2F53ojB02CYQMkLQxqKEj9kk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;469&quot; height=&quot;267&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업의 결과를 보면, 정상적으로 thread2에게 인터럽트가 걸렸다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sleep 상태의 thread2는 인터럽트에 걸려 작업이 종료된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면, 인터럽트 요청이 없는 thread1은 작업이 끝나지 않는다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Thread.currentThread가 아니라, Thread에서 걸어주어도 자신의 스레드만 체크한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메소드를 확인해보면,&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;67&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pbUfW/btsJqQMmYja/FWhtAljcYfFHXDEuJJmts1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pbUfW/btsJqQMmYja/FWhtAljcYfFHXDEuJJmts1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pbUfW/btsJqQMmYja/FWhtAljcYfFHXDEuJJmts1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpbUfW%2FbtsJqQMmYja%2FFWhtAljcYfFHXDEuJJmts1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;418&quot; height=&quot;67&quot; data-origin-width=&quot;418&quot; data-origin-height=&quot;67&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;interrupted()는 안에서 currentThread()를 실행하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 해보길 잘했다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;yield&lt;/b&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 특정한 스레드가 바쁘지 않은 상황에 다른 스레드에게 CPU 실행기회를 양보해 주는 스레드의 메소드&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- yield 메소드를 호출한 스레드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;i&gt;RUNNABLE 상태를 유지하면서 CPU를 양보&lt;/i&gt;&lt;/b&gt;한다&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 짧은 sleep()으로도 상태를 바꿀 수 있지만, TIME_WAITING으로 상태를 변경하고, 짧은 시간 스레드가 멈춘다&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 양보할 스레드가 없으면, 나의 스레드가 실행된다&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;- 최근엔, 많은 코어를 가진 CPU들이 많아서 양보가 큰 의미가 없을 수 있다&lt;/p&gt;</description>
      <category>Java/김영한의 실전자바</category>
      <author>슈코</author>
      <guid isPermaLink="true">https://suco.tistory.com/68</guid>
      <comments>https://suco.tistory.com/68#entry68comment</comments>
      <pubDate>Tue, 3 Sep 2024 21:28:25 +0900</pubDate>
    </item>
    <item>
      <title>스레드 - join()</title>
      <link>https://suco.tistory.com/67</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;join()&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 스레드가 다른 스레드들의 작업이 끝난 후, 무언가를 종합해서 하고 싶다면 join() 메소드를 사용해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스레드1 - 1 ~ 50의 합을 구한다&lt;/li&gt;
&lt;li&gt;스레드2 - 51 ~ 100의 합을 구한다&lt;/li&gt;
&lt;li&gt;메인 - 스레드1,2의 결과값의 합을 구한다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public static void main(String[] args) {
        log(&quot;start&quot;);
        SumTask task1 = new SumTask(1, 50);
        SumTask task2 = new SumTask(51, 100);
        Thread thread1 = new Thread(task1, &quot;task1&quot;);
        Thread thread2 = new Thread(task2, &quot;task2&quot;);

        thread1.start();
        thread2.start();

        log(&quot;task1.result = &quot; + task1.result);
        log(&quot;task2.result = &quot; + task2.result);
        int sumAll = task1.result + task2.result;
        log(&quot;task1 + task2 = &quot; + sumAll);

        log(&quot;end&quot;);
    }

    static class SumTask implements Runnable {

        int startValue;
        int endValue;
        int result = 0;

        public SumTask(int startValue, int endValue) {
            this.startValue = startValue;
            this.endValue = endValue;
        }

        @Override
        public void run() {
            log(&quot;작업 시작&quot;);
            sleep(2000);
            int sum = 0;
            for (int i = startValue; i &amp;lt; endValue; i++) {
                sum += i;
            }
            result = sum;
            log(&quot;작업 완료 result = &quot; + result);
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메인은 thread1과 thread2에게 각각 task1, task2를 시키고 그 결과를 합한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 실행해보면 원하는 결과값이 나오지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWDziG/btsJhkfEzQG/UnUG7QrbFk9thKbDxEULr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWDziG/btsJhkfEzQG/UnUG7QrbFk9thKbDxEULr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWDziG/btsJhkfEzQG/UnUG7QrbFk9thKbDxEULr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWDziG%2FbtsJhkfEzQG%2FUnUG7QrbFk9thKbDxEULr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;404&quot; height=&quot;200&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;200&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main은 thread1과 thread2에게 작업을 시키고, 그것을 기다리지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main은 바로 main의 일을 이어서 진행하기 떄문에, 빈값이 찍히게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;385&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvXlPc/btsJh8adxd8/BBUdJv60kkOCP5QYRDMmF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvXlPc/btsJh8adxd8/BBUdJv60kkOCP5QYRDMmF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvXlPc/btsJh8adxd8/BBUdJv60kkOCP5QYRDMmF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvXlPc%2FbtsJh8adxd8%2FBBUdJv60kkOCP5QYRDMmF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1212&quot; height=&quot;385&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;여기서, thread1과 thread2는 각각의 스택에 run() 메소드를 올리고 실행한다.&lt;br /&gt;task1, task2는 힙 영역에 할당되어서 공유하는 방식이다.&amp;nbsp;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;스레드는 메서드의 호출을 관리하는데,&lt;br /&gt;메서드 단위로 스택 프레임을 만들고, 그 위에 스택을 쌓아 올린다.&lt;br /&gt;인스턴스의 메소드 호출 시, 해당 인스턴스의 참조값을 저장하는데 이를 'this'라고 한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main이 thread1과 thread2의 작업을 기다리기 위해서 join()을 사용해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// 스레드가 종료될 때 까지 대기
log(&quot;join() - main 스레드가 thread1, thread2 종료까지 대기&quot;);
thread1.join();
thread2.join();
log(&quot;main 스레드 대기 완료&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 join() 메소드를 thread1과 thread2의 스레드 시작(start)후에 넣어주면 다음과 같은 결과가 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;626&quot; data-origin-height=&quot;245&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHHeLU/btsJfoKMpfI/jovi542QBtdmrD7Lm3JC90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHHeLU/btsJfoKMpfI/jovi542QBtdmrD7Lm3JC90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHHeLU/btsJfoKMpfI/jovi542QBtdmrD7Lm3JC90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHHeLU%2FbtsJfoKMpfI%2Fjovi542QBtdmrD7Lm3JC90%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;626&quot; height=&quot;245&quot; data-origin-width=&quot;626&quot; data-origin-height=&quot;245&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;join()의 영향으로 main은 thread1, thread2의 종료까지 대기한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 스레드가 종료되면, main은 다시 RUNNABLE 상태가 되어서 원래 임무를 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;join() - 특정 시간 대기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대상 스레드가 완료될 때 까지 기다리는건 비효율적일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;join(ms)를 활용하면, 특정 스레드의 완료까지 대기하지만 입력한 시간이 지나면 빠져나오도록 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;thread1.join(1000);&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 '메인 스레드가 thread1의 종료까지 1초동안 대기한다.' 라고 생각하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;끝날때까지 기다려야 하는 로직을 작성해야하면 join()을, limit time을 지정해줘야 하면 join(ms)를 활용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간에 나올때, 결과가 없으면 그에 맞는 추가 로직을 작성해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sleep()을 활용하기엔, 스레드가 정확히 얼마만큼의 대기와 스케줄링이 걸리는지 100% 장담할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;예제를 통해서&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 3초동안 작업을 하는 스레드가 있다.&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(new MyTask(), &quot;t1&quot;);
    Thread t2 = new Thread(new MyTask(), &quot;t2&quot;);
    Thread t3 = new Thread(new MyTask(), &quot;t3&quot;);

    t1.start();
    t1.join();

    t2.start();
    t2.join();

    t3.start();
    t3.join();

    System.out.println(&quot;모든 스레드 실행 완료&quot;);
}

public static class MyTask implements Runnable {

    @Override
    public void run() {
        for (int i = 1; i &amp;lt;= 3; i++) {
            log(i);
            sleep(1000);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드 하나 당 join()을 걸어서 기다려주고, 해당 작업이 끝나야 다음 작업을 시작하도록 하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 되면, 시간은 총 9초가 걸리게 된다(t1, t2, t3 각 3초씩)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동시에 처리하려면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 join() 메소드는 모든 스레드의 start() 메소드 이후에 실행해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(new MyTask(), &quot;t1&quot;);
    Thread t2 = new Thread(new MyTask(), &quot;t2&quot;);
    Thread t3 = new Thread(new MyTask(), &quot;t3&quot;);

    t1.start();
    t2.start();
    t3.start();

    t2.join();
    t1.join();
    t3.join();

    System.out.println(&quot;모든 스레드 실행 완료&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이, 실행해주면 3초의 시간에 모든 작업이 끝나게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 항상 아래와 같은 방식으로 해줘야하는건 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 전 작업이 끝나야 다음 작업을 수행하는 경우라면 아래의 방법을 사용해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;( 그렇지만... 모든 작업이 끝나야 다음 작업을 실행하는 경우라면, 굳이 멀티스레드를 도입해서 복잡성을 높일 필요는 없을거 같다! )&lt;/p&gt;</description>
      <category>Java/김영한의 실전자바</category>
      <author>슈코</author>
      <guid isPermaLink="true">https://suco.tistory.com/67</guid>
      <comments>https://suco.tistory.com/67#entry67comment</comments>
      <pubDate>Mon, 26 Aug 2024 21:51:28 +0900</pubDate>
    </item>
    <item>
      <title>스레드 제어</title>
      <link>https://suco.tistory.com/66</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;쓰레드 기본 정보&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;스레드 ID&lt;/b&gt; - 스레드의 &lt;b&gt;고유 식별자&lt;/b&gt;, 스레드 생성 시 할당되고, 지정할 수 없다.&lt;/li&gt;
&lt;li&gt;스레드 이름 - 내가 지정할 수 있고, 중복될 수 있다.&lt;/li&gt;
&lt;li&gt;스레드 우선순위 - 1(낮음) ~ 10(높음), 기본값은 5, 절대적인 실행순서는 아니다.(힌트)&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;힌트라는 말은, 스케줄러가 '참고'하는 대상으로 인식한다는 정도&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;스레드 그룹 - 스레드가 속한 그룹, 자주 사용하지는 않음&lt;/li&gt;
&lt;li&gt;부모 스레드 - 모든 스레드는(main 제외) 누군가가 생성해준다. 나를 생성해준 스레드가 부모 스레드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스레드 상태&lt;/b&gt; - 스레드의 현재 상태
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NEW - 스레드가 생성되고 아직 실행되진 않은 상태&lt;/li&gt;
&lt;li&gt;RUNNABLE - 스레드를 실행중이거나, 실행될 준비가 된 상태&lt;/li&gt;
&lt;li&gt;BLOCKED - 동기화 락을 기다리는 상태&lt;/li&gt;
&lt;li&gt;WATING - 다른 스레드의 작업이 완료되기를 기다리는 상태&lt;/li&gt;
&lt;li&gt;TIMED_WATING - '일정기간' 동안 기다리는 상태&lt;/li&gt;
&lt;li&gt;TERMINATED - 스레드가 실행을 마친 상태
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한번 종료된 스레드는 다시 실행할 수 없다.&lt;/li&gt;
&lt;li&gt;스레드마다 주어진 스택이 텅 비어지기 떄문에&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;쓰레드 생명주기&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;NEW
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스레드 생성 후 시작되지 않은 상태&lt;/li&gt;
&lt;li&gt;Thread 객체 생성, start() 메소드 실행 전&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;RUNNABLE
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스레드가 실행될 준비가 된 상태&lt;/li&gt;
&lt;li&gt;start() 메소드 호출 시 해당 상태로 진입&lt;/li&gt;
&lt;li&gt;모든 스레드가 동시에 실행되는 것은 아니다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;운영체제의 스케줄러에 의해 CPU 시간을 할당&lt;/li&gt;
&lt;li&gt;스케줄러의 대기열에 포함되어 차례대로 실행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;너무나 빠르게 실행과 대기열 대기가 반복되기 때문에 이 상태를 구분할 수 없다&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;'실행 상태' 라고도 부른다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;BLOCKED
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 스레드에 의해 동기화 락을 얻기 위해 기다리는 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;WAITING
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다른 스레드의 특정 작업이 끝나기를 기다리는 상태&lt;/li&gt;
&lt;li&gt;wait(), join() 메서드 호출 시&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TIMED WAITING
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 시간동안 다른 스레드의 작업이 끝나기를 기다리는 상태&lt;/li&gt;
&lt;li&gt;'특정 시간'이라는 제한이 들어간다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;TERMINATED
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스레드 실행 완료&lt;/li&gt;
&lt;li&gt;정상 종료 or 예외 종료&lt;/li&gt;
&lt;li&gt;종료되면, 다시 시작할 수 없다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>Java/김영한의 실전자바</category>
      <author>슈코</author>
      <guid isPermaLink="true">https://suco.tistory.com/66</guid>
      <comments>https://suco.tistory.com/66#entry66comment</comments>
      <pubDate>Thu, 22 Aug 2024 21:47:21 +0900</pubDate>
    </item>
    <item>
      <title>제네릭</title>
      <link>https://suco.tistory.com/65</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;제네릭이 필요한 이유( Box 예제 )&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;i&gt; &lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;타입 안전성을 높이면서, 코드를 재사용하기 위해&lt;/span&gt; &lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;Integer 변수 value를 set, get을 할 수 있는 IntegerBox 클래스 생성&lt;/p&gt;
&lt;pre class=&quot;cs&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class IntegerBox {

    private Integer value;

    public void set(Integer value) {
        this.value = value;
    }

    public Integer get() {
        return value;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;String 변수 value를 set, get을 할 수 있는 StringBox 클래스 생성&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public class StringBox {

    private String value;

    public void set(String value) {
        this.value = value;
    }

    public String get() {
        return value;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;한가지 타입에 대한 같은 기능이지만, 타입을 추가할떄마다 매번 클래스를 새로 만들어야하는 &lt;b&gt;&lt;i&gt;불편함&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;모든 타입의 부모인 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;i&gt;&lt;b&gt;Object 타입&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;으로 생성하여, 문제 해결 시도&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class ObjectBox {

    private Object value;

    public Object get() {
        return value;
    }

    public void set(Object value) {
        this.value = value;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;get을 할때 Object 타입으로 리턴을 해주기 때문에 맞는 타입을 리턴받으려면 &lt;b&gt;&lt;i&gt;캐스팅을 매번 해줘야 한다&lt;/i&gt;&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;잘못된 타입(Integer만 set 하려고 했는데, String을 set)을 저장하면, 캐스팅 시 에러가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;코드 재사용은 가능했지만, &lt;i&gt;&lt;b&gt;에러가 발생할 이슈&lt;/b&gt;&lt;/i&gt; 존재&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타입별로 클래스를 생성 - 타입의 안전성 &amp;uarr;&amp;nbsp; 코드 재사용성 &amp;darr;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Object -&amp;nbsp; 코드 재사용성&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;uarr;&amp;nbsp; 타입 안전성&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&amp;darr;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;제네릭 클래스&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&amp;lt;&amp;gt;&lt;/b&gt;를 사용한 클래스&lt;/li&gt;
&lt;li&gt;&amp;lt;&amp;gt; = 다이아몬드&lt;/li&gt;
&lt;li&gt;클래스 오른쪽에 &amp;lt;T&amp;gt; 표현 = 제네릭 클래스&lt;/li&gt;
&lt;li&gt;T = 타입 매개변수&lt;/li&gt;
&lt;li&gt;생성 시점에 타입을 적어 클래스 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;제네릭 타입 Box로 이슈해결&lt;/b&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class GenericBox&amp;lt;T&amp;gt; {

    private T value;

    public void set(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;GenericBox&amp;lt;T&amp;gt;를 선언, Integer로 사용하고 싶으면&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;GenericBox&amp;lt;Integer&amp;gt; integerBox = new GenericBox&amp;lt;Integer&amp;gt;();&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;다음과 같이 '생성' 시점에 Integer를 적어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;( 코드 재사용성 &amp;uarr; )&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;여기서 오른쪽에 Integer는 생략이 가능하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;( 왼쪽에 생성할때, Integer를 적어주기 때문에, 추론이 가능하다 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;GenericBox&amp;lt;&amp;gt; integerBox = new GenericBox&amp;lt;Integer&amp;gt;() ;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;Integer로 생성하면, String으로 값을 set 하는 순간 컴파일 에러가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;( 타입 안전성 &amp;uarr; )&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public static void main(String[] args) {

    GenericBox&amp;lt;Integer&amp;gt; integerBox = new GenericBox&amp;lt;Integer&amp;gt;(); // 생성 시점에 T의 타입 결정(Integer로)
    integerBox.set(10);
    Integer integer = integerBox.get(); // Integer 타입만 허용, 컴파일 오류
    System.out.println(&quot;integer = &quot; + integer);

    GenericBox&amp;lt;String&amp;gt; stringBox = new GenericBox&amp;lt;String&amp;gt;();
    stringBox.set(&quot;hello&quot;);
    String str = stringBox.get();
    System.out.println(&quot;str = &quot; + str);

    // 원하는 모든 타입 사용 가능
    GenericBox&amp;lt;Double&amp;gt; doubleBox = new GenericBox&amp;lt;&amp;gt;();
    doubleBox.set(10.0);
    Double doubleValue = doubleBox.get();
    System.out.println(&quot;doubleValue = &quot; + doubleValue);
    
    // 타입 추론 : 생성하는 제네릭 타입 생략 가능
    GenericBox&amp;lt;Integer&amp;gt; integerBox2 = new GenericBox&amp;lt;&amp;gt;();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;제네릭의 핵심&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;사용할 타입을 미리 결정하지 않는다. 생성 시점에 지정한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;클래스 내부에서 사용하는 타입을 정의하는 시점이 아닌, &lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;&lt;i&gt;생성하는 시점에 결정&lt;/i&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;용어정리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제네릭 - 일반적인, 범용적인 뜻( 특정 타입에 속한 것 이 아니라, 범용적으로 사용할 수 있다! )&lt;/li&gt;
&lt;li&gt;제네릭 타입 - 클래스, 인터페이스 정의 시 타입 매개변수를 사용하는 것&lt;/li&gt;
&lt;li&gt;타입 매개변수 - 제네릭 타입, 메서드에서 사용하는 변수로 실제 타입으로 대체된다&lt;/li&gt;
&lt;li&gt;타입 인자 - 제네릭 타입을 사용할때, 제공되는 실제 타입&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;GenericBox&amp;lt;T&amp;gt;&lt;br /&gt;String - Generic&amp;lt;String&amp;gt;&lt;br /&gt;Integer - Generic&amp;lt;Integer&amp;gt;&lt;br /&gt;&lt;br /&gt;T를 타입 매개변수,&lt;br /&gt;String, Integer를 타입인자&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;메소드 매개변수 &amp;amp; 제네릭 매개변수&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메소드 매개변수 = 사용할 값에 대한 결정을 나중으로 미룬다.&lt;/li&gt;
&lt;li&gt;제네릭 매개변수 = 사용할 타입에 대한 결정을 나중으로 미룬다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;제네릭 명명 관례&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;E - Element&lt;/li&gt;
&lt;li&gt;K - Key&lt;/li&gt;
&lt;li&gt;N - Number&lt;/li&gt;
&lt;li&gt;T - Type&lt;/li&gt;
&lt;li&gt;V - Value&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;제네릭 기타&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한번에 여러 타입을 지정할 수 있다( &amp;lt;K, T&amp;gt; )&lt;/li&gt;
&lt;li&gt;항상 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;&amp;lt;&amp;gt;&lt;/b&gt;&lt;/span&gt;을 사용해서 사용시점에 원하는 타입을 지정해야 한다&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;&amp;lt;&amp;gt;&lt;/b&gt;&lt;/span&gt;을 생략하면, 원시타입(매개변수가 Object로 사용)&lt;/li&gt;
&lt;li&gt;원시타입은 제네릭이 생기기 전의 코드와 호환성을 위해&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;타입 매개변수 제한&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제네릭 사용 시 특정 타입으로 타입 매개변수를 제한할때 사용&lt;/li&gt;
&lt;li&gt;&amp;lt;T extend 클래스명&amp;gt;&lt;/li&gt;
&lt;li&gt;extend 옆에 붙어있는 클래스명 자신, 혹은 그 자식들만 사용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Animal 객체 예시를 통하여 타입 매개변수를 제한하는 것의 장점을 파악할 수 있다.&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class Animal {

    private String name;
    private int size;

    public Animal(String name, int size) {
        this.name = name;
        this.size = size;
    }

    public String getName() {
        return name;
    }

    public int getSize() {
        return size;
    }

    public void sound() {
        System.out.println(&quot;동물 울음 소리&quot;);
    }

    @Override
    public String toString() {
        return &quot;Animal{&quot; +
                &quot;name='&quot; + name + '\'' +
                &quot;, size=&quot; + size +
                '}';
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;name과 size를 가지는 Animal 클래스, get() 메소드와 sound(): 동물 울음소리 출력 메소드를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;public class Dog extends Animal {


    public Dog(String name, int size) {
        super(name, size);
    }

    @Override
    public void sound() {
        System.out.println(&quot;멍멍&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Animal 클래스를 상속받은 Dog 클래스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;public class Cat extends Animal {

    public Cat(String name, int size) {
        super(name, size);
    }

    @Override
    public void sound() {
        System.out.println(&quot;야옹&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 Animal 클래스를 상속받은 Cat 클래스&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class DogHospital {

    private Dog animal;

    public void set(Dog animal) {
        this.animal = animal;
    }

    public void checkup() {
        System.out.println(&quot;동물 이름 : &quot; + animal.getName());
        System.out.println(&quot;동물 크기 : &quot; + animal.getSize());
        animal.sound();
    }

    public Dog bigger(Dog target) {
        return animal.getSize() &amp;gt; target.getSize() ? animal : target;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dog 클래스를 활용하여 만든 DogHospital 클래스, checkup()과 bigger() 메소드를 가진다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class CatHospital {

    private Cat animal;

    public void set(Cat animal) {
        this.animal = animal;
    }

    public void checkup() {
        System.out.println(&quot;동물 이름 : &quot; + animal.getName());
        System.out.println(&quot;동물 크기 : &quot; + animal.getSize());
        animal.sound();
    }

    public Cat bigger(Cat target) {
        return animal.getSize() &amp;gt; target.getSize() ? animal : target;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Cat 클래스를 활용하여 만든 CatHospital 클래스, 역시 checkup()과 bigger() 메소드를 가진다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;public class AnimalHospitalMainV0 {

    public static void main(String[] args) {
        DogHospital dogHospital = new DogHospital();
        CatHospital catHospital = new CatHospital();

        Dog dog = new Dog(&quot;멍멍이1&quot;, 100);
        Cat cat = new Cat(&quot;고양이1&quot;, 300);

        // 개 병원
        dogHospital.set(dog);
        dogHospital.checkup();

        // 고양이 병원
        catHospital.set(cat);
        catHospital.checkup();

        // 문제 1: 개 병원에 고양이 전달
        //dogHospital.set(cat); 다른타입을 입력하면 컴파일 오류

        // 문제 2: 개 타입 반환
        dogHospital.set(dog);
        Dog biggerDog = dogHospital.bigger(new Dog(&quot;멍멍이2&quot;, 200));
        System.out.println(&quot;biggerDog = &quot; + biggerDog);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DogHospital, CatHospital 클래스를 만들어 Dog, Cat을 넣어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 클래스는 그에 맞는 동물 클래스만 들어갈 수 있어서 DogHospital에 Cat 객체를 넣으면 컴파일 오류가 발생한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, &lt;b&gt;&lt;i&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;같은 기능을 수행&lt;/span&gt;하는 중복되는 클래스를 만든 이슈가 있다.&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class AnimalHospitalV1 {

    private Animal animal;

    public void set(Animal animal) {
        this.animal = animal;
    }

    public void checkup() {
        System.out.println(&quot;동물 이름 : &quot; + animal.getName());
        System.out.println(&quot;동물 크기 : &quot; + animal.getSize());
        animal.sound();
    }

    public Animal bigger(Animal target) {
        return animal.getSize() &amp;gt; target.getSize() ? animal : target;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dog, Cat 클래스의 부모 클래스인 Animal 클래스를 활용한 AnimalHospital 클래스를 만들어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각 만들 필요 없이 Dog, Cat 클래스를 모두 넣을 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;public class AnimalHospitalMainV1 {

    public static void main(String[] args) {
        AnimalHospitalV1 dogHospital = new AnimalHospitalV1();
        AnimalHospitalV1 catHospital = new AnimalHospitalV1();

        Dog dog = new Dog(&quot;멍멍이1&quot;, 100);
        Cat cat = new Cat(&quot;고양이1&quot;, 300);

        // 개 병원
        dogHospital.set(dog);
        dogHospital.checkup();

        // 고양이 병원
        catHospital.set(cat);
        catHospital.checkup();

        // 문제 1: 개 병원에 고양이 전달
        dogHospital.set(cat);  // 매개변수 체크 실패 : 컴파일 오류가 발생하지 않는다.

        // 문제 2: 개 타입 반환
        dogHospital.set(dog);
        Dog biggerDog = (Dog) dogHospital.bigger(new Dog(&quot;멍멍이2&quot;, 200));
        System.out.println(&quot;biggerDog = &quot; + biggerDog);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Dog, Cat 클래스를 활용한 Hospital 클래스 없이도 모든 동물을 넣을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, DogHospital로 만들어도 Cat 클래스를 넣을 수 있다(매개변수 체크 실패: 컴파일 오류가 발생하지 않음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bigger() 메소드 사용 시 형 변환을 사용해야 하는 경우가 발생한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;매개변수 제한 없이 제네릭을 활용하면, 모든 타입이 들어갈 수 있다&lt;br /&gt;또한, Animal에서 만든 메소드를 사용하지 못한다&lt;br /&gt;(어떤 타입이 들어갈지 알 수 없기 때문에, Object의 기본 메소드만 활용가능)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;public class AnimalHospitalV3&amp;lt;T extends Animal&amp;gt; {

    private T animal;

    public void set(T animal) {
        this.animal = animal;
    }

    public void checkup() {
        System.out.println(&quot;동물 이름 : &quot; + animal.getName());
        System.out.println(&quot;동물 크기 : &quot; + animal.getSize());
        animal.sound();
    }

    public T bigger(T target) {
        return animal.getSize() &amp;gt; target.getSize() ? animal : target;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제네릭 선언 시, 매개변수 타입 제한을 활용하면, Animal 클래스 자신과 자식 클래스만 제네릭 타입으로 선언할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Animal 클래스의 메소드를 활용할 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자식 클래스는, 오버라이딩 되어서 자식 클래스의 메소드를 활용할 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #1e1f22; color: #bcbec4;&quot;&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;public class AnimalHospitalMainV3 {

    public static void main(String[] args) {
        AnimalHospitalV3&amp;lt;Dog&amp;gt; dogHospital = new AnimalHospitalV3&amp;lt;&amp;gt;();
        AnimalHospitalV3&amp;lt;Cat&amp;gt; catHospital = new AnimalHospitalV3&amp;lt;&amp;gt;();

        Dog dog = new Dog(&quot;멍멍이1&quot;, 100);
        Cat cat = new Cat(&quot;고양이1&quot;, 300);

        // 개 병원
        dogHospital.set(dog);
        dogHospital.checkup();

        // 고양이 병원
        catHospital.set(cat);
        catHospital.checkup();

        // 문제 1: 개 병원에 고양이 전달
        //dogHospital.set(cat);  // 다른 타입을 입력: 컴파일 오류

        // 문제 2: 개 타입 반환
        dogHospital.set(dog);
        Dog biggerDog = dogHospital.bigger(new Dog(&quot;멍멍이2&quot;, 200));
        System.out.println(&quot;biggerDog = &quot; + biggerDog);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동물 클래스 별로 만들 필요가 없어 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;i&gt;&lt;b&gt;중복을 제거&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;하고, &lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;i&gt;&lt;b&gt;다른 타입이 들어오는 것을 방지&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;할 수 있다(컴파일 오류 발생)&lt;/p&gt;</description>
      <category>Java/김영한의 실전자바</category>
      <author>슈코</author>
      <guid isPermaLink="true">https://suco.tistory.com/65</guid>
      <comments>https://suco.tistory.com/65#entry65comment</comments>
      <pubDate>Thu, 15 Aug 2024 12:42:19 +0900</pubDate>
    </item>
    <item>
      <title>아빠가 되다</title>
      <link>https://suco.tistory.com/63</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;2024년 4월 25일 내 인생에 가장 큰 이벤트가 발생하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;용용이(태명)가 태어난 것 이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;나는 그렇게 아빠가 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;사실 출산예정일은 5월 12일이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;그래서, 마음의 준비를 미처 하지 못하고 용용이를 맞이하러 내려갔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;뜻밖의 전화&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;새벽 6시에 아내에게 전화가 왔었는데, 밤 12시30분부터 진통이 시작되었다고 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;처음에는 가진통이겠지 싶어서 가족들에게 이야기하지 않았다고 한다ㅠㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;아내는 극심한 고통을 이겨내며, 새벽에 장모님께서 아내를 발견하기 전까지 혼자 참아왔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;이런 부분은 주말부부를 하고 있는 것 중에 가장 미안한 부분인거 같다ㅠ&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;KTX&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;나는 서둘러 내려갈 준비를 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;정말 운이 좋게도? 전날부터 벨소리를 진동이 아닌 소리로 바꿔두었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;바꾼 첫날에 연락이 올지는 몰랐지만...&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;머리도 감지 못하고 급하게 집을 출발하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;서울에서 전주로 가는 가장 빠른 KTX는&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;용산에서 출발하는 07시 10분과 07시 43분이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;07시 10분은 08시 54분에 전주에 도착, 07시 43분은 09시 57분에 전주에 도착하는 기차였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;빠른 준비?로 다행히 07시 10분 기차에 탑승할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;( 용용이가 태어난 시각이 09시 44분이라서 다음 기차를 탔다면 용용이가 태어나는걸 보지 못했을 것 이다! )&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;기차안에서 무엇을 할 수 있을까...&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;아내에게 빨리 가고싶은 생각뿐이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;KTX를 이용하면 서울에서 전주까지 2시간 안으로 갈 수 있는 시대이지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;그 2시간이 안되는 시간도 너무 길게 느껴졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;그렇게 아이의 탄생을 직접 볼 수 있었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;탯줄을 잘라 줄 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;아이가 태어나기전, 회사와 의논하여 아내의 산후조리원 기간에 재택근무를 할 수 있었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;아내의 회복을 곁에서 도울 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;그렇게, 용용이는 도훈이라는 이름을 가진 우리의 아들이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;중간에 도훈이는 복무팽만이 있어서 중환자실까지 가는 일이 있었지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;다행히 우려하던 병은 아니였고, 무사히 퇴원해서 무럭무럭 자라고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;100일을 넘어간 시점에 10키로에 가까워지고 있다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;한동안 블로그를 포함해서, 신경쓸 겨를이 없었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;아이를 바라보고 있으면, 정말이지 행복하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;그렇지만 주말부부라는 특징으로 아이를 보는 것도 주말뿐이다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;매일 고생하고 있는 아내를 보면, 매주 커가는 아이를 보고 있으면 시간을 더 잘 보내야겠다는 생각뿐이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;다시 블로그도 열심히 하면서 평일에도 최선을 다해보아야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>생각정리</category>
      <author>슈코</author>
      <guid isPermaLink="true">https://suco.tistory.com/63</guid>
      <comments>https://suco.tistory.com/63#entry63comment</comments>
      <pubDate>Thu, 15 Aug 2024 12:17:58 +0900</pubDate>
    </item>
    <item>
      <title>스레드의 생성과 실행</title>
      <link>https://suco.tistory.com/62</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;스레드의 생성&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Runnable 인터페이스 구현을 사용하자&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Thread 클래스 상속&lt;/li&gt;
&lt;li&gt;Runnable 인터페이스 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드는 Thread 클래스를 상속해서 만들거나, Runnable 인터페이스를 구현하는 방법으로 생성할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실무에서는 Runnable 인터페이스를 구현하는 방법을 선호&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Thread 클래스를 상속하는 경우, 다른 상속이 있는 경우에는 사용할 수 없다( 다중 상속 X )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 스레드와 실행할 작업을 명확히 나누어서 개발할 수 있는 &lt;b&gt;Runnable 방식을 사용&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;스레드 생성 - Thread 클래스 상속&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Thread 클래스 상속 후 run() 메소드를 오버라이딩한다.&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class HelloThread extends Thread {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + &quot; : run()&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 생성 후 start() 메소드를 사용하여 실행한다.&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class HelloThreadMain {
    public static void main(String[] args) {
        HelloThread helloThread = new HelloThread();
        helloThread.start();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;스레드 생성 - Runnable 인터페이스 구현&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Runnable 인터페이스를 구현하는 클래스를 만들고, Thread 객체를 생성할때 생성자로 넣어준다.&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class HelloRunnable implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + &quot;: run()&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class HelloRunnableMain {
    public static void main(String[] args) {
        HelloRunnable runnable = new HelloRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Runnable을 이용하여 다양한 방법으로 스레드를 생성할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가장 기본&lt;/b&gt;적으로, Runnable 인터페이스를 구현하고 이를 스레드 생성 시 파라미터로 넣어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;기본&amp;gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class InnerRunnableMainV1 {

    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
    }

    static class MyRunnable implements Runnable {
        @Override
        public void run() {
            log(&quot;run()&quot;);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 &lt;b&gt;익명클래스&lt;/b&gt;를 사용하여 만들 수 있고, 이는 &lt;b&gt;람다&lt;/b&gt;로 간단하게 표현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익명클래스를 사용하는 경우는, 재사용없이 간단히 표현해줄때 사용하면 효과적일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 재사용이 많은 경우에는, 따로 선언해놓는 방법이 효율적이다. )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;익명클래스&amp;gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class InnerRunnableMainV2 {

    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                log(&quot;run()&quot;);
            }
        });
        thread.start();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;람다 표현식&amp;gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class InnerRunnableMainV2 {

    public static void main(String[] args) {
        Thread thread = new Thread(() -&amp;gt; log(&quot;run()&quot;));
        thread.start();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 &lt;b&gt;람다를 사용한 이 방식&lt;/b&gt;을 자주 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;람다의 경우 다음번에 정리하는 시간을 가져야겠다.( 2024년 8월 19일 기준! )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Runnable의 경우, 한번 만들어둔 것을 &lt;b&gt;반복해서 호출&lt;/b&gt; 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨 위에 예시 HelloRunnable을 가져와서 반복 생성해보자.&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class ManyThreadMainV1 {

    public static void main(String[] args) {
        HelloRunnable runnable = new HelloRunnable();

        Thread thread1 = new Thread(runnable);
        thread1.start();

        Thread thread2 = new Thread(runnable);
        thread2.start();

        Thread thread3 = new Thread(runnable);
        thread3.start();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;스레드의 실행&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;start() 메소드 호출( run() 메소드 호출 x )&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만들어둔 스레드 객체를 생성하고, start() 메소드를 실행한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;run() 메소드가 아닌, start() 메소드를 호출해줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( start()를 호출해야, 별도 스레드에서 run()을 호출해줌 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;run() 메소드를 호출&lt;/b&gt;하는 경우, 별도의 스레드가 생성되면서 그 스레드가 run()을 호출하는 것이 아닌,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;현재 스레드가 단순히 run() 메소드를 실행&lt;/b&gt;하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 스레드를 생성해서 그 스레드가 run()을 실행하려고 했던 원래 의도에서 벗어남 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;스레드 메소드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;currentThread() - 해당 코드를 실행하는 스레드의 정보 조회&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;currentThread().getName() - 실행중인 스레드의 이름 조회&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 별도의 이름을 입력해주지 않으면, thread-0, thread-1 등으로 임의 생성된다 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;데몬 스레드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백그라운드에서 &lt;b&gt;보조&lt;/b&gt; 작업을 수행하는 스레드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드는 사용자 스레드와 데몬 스레드로 구분할 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( Thread 메소드 setDaemon()을 true로 하면 데몬스레드, 디폴트는 false )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모든 유저 스레드가 종료되면, 데몬 스레드는 자동으로 종료된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;로거&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드를 실행할때는 로그를 남기는 것 이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 어떤 스레드가 실행되었는지를 알아야 하기 때문에 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그를 남기는 메소드를 따로 구성하자!&lt;/p&gt;
&lt;div style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public abstract class MyLogger {

    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(&quot;HH:mm:ss.SSS&quot;);

    public static void log(Object obj) {
        String time = LocalTime.now().format(formatter);
        System.out.printf(&quot;%s [%9s] %s\n&quot;, time, Thread.currentThread().getName(), obj);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java/김영한의 실전자바</category>
      <author>슈코</author>
      <guid isPermaLink="true">https://suco.tistory.com/62</guid>
      <comments>https://suco.tistory.com/62#entry62comment</comments>
      <pubDate>Thu, 15 Aug 2024 10:14:04 +0900</pubDate>
    </item>
    <item>
      <title>프로세스와 스레드</title>
      <link>https://suco.tistory.com/61</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;멀티태스킹&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 컴퓨터 시스템이 동시에 여러작업을 수행하는 능력&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어적 관점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 무지하게 빠른 CPU를 잘 활용해보자는 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU가 빠르게 여러가지 프로그램의 코드를 번갈아가며 실행하여, 동시에 실행되는 것 처럼!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;멀티프로세싱&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 이상의 프로세서(CPU 코어)를 사용하여 동시에 여러 작업을 동시에 처리하는 기술&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드웨어적 관점&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 코어의 갯수가 여러가지 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코어의 갯수만큼은 동시에 프로그램을 실행할 수 있는 것!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;프로세스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행중인 프로그램&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램이 &lt;b&gt;클래스&lt;/b&gt;라면, 프로세스는 &lt;b&gt;인스턴스&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스별 독립적인 공간 보유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드섹션, 데이터 섹션, 힙, 스택으로 구분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 스택은 스레드별로 주어지고, 나머지는 프로세스별로 주어진다! )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드를 실행하기 위한 컨테이너의 느낌으로 생각하면 된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;스레드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스 내에서 반드시 하나 이상 존재&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로세스의 &lt;b&gt;코드를 실행하는 흐름&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실질적으로 프로그램 실행 시 프로세스안에 있는 스레드가 CPU의 자원을 활용하여 일을 한다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드별 &lt;b&gt;각자의 스택영역&lt;/b&gt;을 가지고 있고, 나머지 영역은 프로세스안에서 스레드들끼리 공유&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 프로세스 내 하나의 스레드 - 단일스레드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 프로세스 내 여러 스레드 - 멀티스레드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멀티스레드 필요성 - 유튜브 영상보면서 댓글기능 - 영상 스레드, 댓글 스레드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;스케줄링&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU의 시간을 여러 작업에 나누어 &lt;b&gt;분배하는 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 어떤 프로그램이 얼마만큼 실행되는지 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU를 최대한 활용할 수 있는 다양한 기법이 존재&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 필요하면 더 공부할 수 있도록 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;컨텍스트 스위칭&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;문맥을 전환한다.&quot; 라는 뜻을 가짐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;운영체제에서는, 한 스레드 실행 중 스케줄링에 의해 다른 스레드가 실행될때, &lt;b&gt;스레드 간 전환 과정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스레드가 전환하면서, 기존 데이터를 저장하고 새로운 작업을 하도록 하는 작업&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비용이 발생한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 매우 빠르지만 비용이 발생한다는 점 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분 효율적, 그러나 별거 아닌 기능에 너무 많은 전환이 들어가면 비효율적&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;스레드 실무&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 어플리케이션 서버의 경우, &lt;b&gt;I/O Bound&lt;/b&gt;가 자주 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 말은, CPU가 노는 경우가 많이 발생할 수 있다는 것.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해서, CPU 코어와 스레드 갯수를 맞추지 않고 스레드 갯수를 늘려 I/O 작업 시 스레드는 다른 작업을 진행한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 효율성 증가 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 성능 테스트를 통해서, 최적의 스레드 갯수를 찾아야 한다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Java/김영한의 실전자바</category>
      <author>슈코</author>
      <guid isPermaLink="true">https://suco.tistory.com/61</guid>
      <comments>https://suco.tistory.com/61#entry61comment</comments>
      <pubDate>Tue, 13 Aug 2024 19:41:19 +0900</pubDate>
    </item>
  </channel>
</rss>