<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>honguniverse_dev.log</title>
        <link>https://velog.io/</link>
        <description>Developer</description>
        <lastBuildDate>Tue, 07 May 2024 13:05:52 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>honguniverse_dev.log</title>
            <url>https://velog.velcdn.com/images/honguniverse_dev/profile/d4a3d832-e04e-43c9-abf1-3343df6b11a7/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. honguniverse_dev.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/honguniverse_dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[변수의 스코프와 static]]></title>
            <link>https://velog.io/@honguniverse_dev/%EB%B3%80%EC%88%98%EC%9D%98-%EC%8A%A4%EC%BD%94%ED%94%84%EC%99%80-static</link>
            <guid>https://velog.io/@honguniverse_dev/%EB%B3%80%EC%88%98%EC%9D%98-%EC%8A%A4%EC%BD%94%ED%94%84%EC%99%80-static</guid>
            <pubDate>Tue, 07 May 2024 13:05:52 GMT</pubDate>
            <description><![CDATA[<p>변수의 스코프와 static의 개념에 대해 알아보기 전에, 변수의 종류와 메모리 영역에 대하여 알아야 한다. </p>
<h3 id="자바-변수의-종류와-메모리-영역">자바 변수의 종류와 메모리 영역</h3>
<p><img src="https://velog.velcdn.com/images/honguniverse_dev/post/1d599974-beb8-4aa0-ba73-693c4eae12c0/image.png" alt=""></p>
<pre><code class="language-java">public class VariableScopeExam {
    int globalScope = 10;    // 인스턴스 변수
    static int staticVal = 7;    // 클래스 변수(= static 변수)

    public void scopeTest(int value){    // 매개변수
        int localScope = 20;    // 지역변수

        System.out.println(globalScope);
        System.out.println(localScope);
        System.out.println(value);

    }
}</code></pre>
<p>선언 위치에 따라 변수는 선언된 위치에 따라 <strong>클래스변수, 인스턴스변수, 지역변수</strong>로 나눌 수 있다. </p>
<p>메모리 공간(Runtime Data Area)은 크게 <strong>Method(Static) 영역, Stack 영역, Heap 영역</strong>으로 구분되고 데이터 타입(자료형)에 따라 각 영역에 나눠서 할당 되게 된다.</p>
<p><strong>1) Method(Static) 영역</strong></p>
<ul>
<li>클래스와 인터페이스 대한 런타임 상수 풀, 멤버 변수(필드), 클래스 변수(Static 변수), 상수(final), 생성자(constructor)와 메소드(method) 등을 저장하는 공간이다.</li>
<li>클래스가 로딩될 때 생성되며 static 메모리에 있는 데이터들은 프로그램이 종료될 때까지 어디서든 사용이 가능하다.</li>
</ul>
<p>✏️ 여기서 static이 붙지 않은 일반 인스턴스 변수들은 static 영역에 들어가지 않으며, 전역변수와 정적 맴버 변수(static 으로 선언되는 것)들의 데이터를 저장한다고 기억하고 있으면 된다. </p>
<p><strong>2) Stack 영역</strong></p>
<ul>
<li>스택 영역은 기본 자료형을 생성할 때 저장하는 공간으로, 임시적으로 사용되는 변수나 정보들이 저장되는 영역이다.</li>
<li>참조 자료형은 참조값만 저장한다. 이 참조값은 heap 영역에 존재하는 인스턴스(객체)를 가르키는데 사용한다. </li>
</ul>
<p><strong>3) Heap 영역</strong></p>
<ul>
<li>참조형(Reference Type)의 데이터 타입을 갖는 객체, 배열 등은 Heap 영역에 저장된다.</li>
</ul>
<p>✏️ new를 통해 인스턴스 객체를 생성했을 때, heap 영역에는 생성된 객체가 올라가고, Stack 영역에는 해당 객체에 대한 주소 값(Reference)이 저장하는 것이다.</p>
<hr>
<h3 id="static">static</h3>
<p>static은 &#39;정적인&#39; 이라는 뜻을 가지고 있으며, static이 앞에 붙는 변수나 메서드는 어떤 객체에 소속되는 것이 아닌, <strong>클래스에 고정되어 있는 변수나 메서드이다.</strong></p>
<p>따라서 객체 생성 없이 사용할 수 있으며, 위에서 설명하였듯이 메모리에 고정적으로 할당된다. 프로그램이 시작되면 메모리의 static 영역에 적재되고, 프로그램이 종료될 때 해제된다.</p>
<p>여기서 <strong>주의하여할 점은, static 메서드 내에서는 인스턴스 변수를 사용할 수 없다는 것이다.</strong> 이는 static한 메서드가 사용되는 시점에 해당 클래스가 인스턴스화되지 않았을 수도 있기 때문이다. 
쉽게 말하면 static 메서드는 는 객체 생성 없이 사용할 수 있는데, 인스턴스 변수는 객체의 속성이므로 사용할 수 없는 것이다. 따라서 static 메서드 내에서 인스턴스 변수를 사용하면 컴파일 오류가 발생한다!</p>
<p>또 static한 필드는 인스턴스를 생성할 때 만들어지는 것이 아니라고 하였으므로, <strong>값을 저장할 수 있는 공간도 하나밖에 없다. 즉 값을 공유하는 것이다.</strong> 그래서 같은 클래스에 대해 2개의 인스턴스를 생성하여 static 변수에 각각 다르게 값을 할당하여도 공유하기 때문에 최종적으로 할당한 값이 출력될 것이다. </p>
<p>_변하지 않는 값이라면 final을 붙여 생성해야 한다.
_</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[인프런 김영한 강의, 스프링 핵심 원리 - 기본편 / 수료증 및 후기]]></title>
            <link>https://velog.io/@honguniverse_dev/%EC%9D%B8%ED%94%84%EB%9F%B0-%EA%B9%80%EC%98%81%ED%95%9C-%EA%B0%95%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8-%EC%88%98%EB%A3%8C%EC%A6%9D</link>
            <guid>https://velog.io/@honguniverse_dev/%EC%9D%B8%ED%94%84%EB%9F%B0-%EA%B9%80%EC%98%81%ED%95%9C-%EA%B0%95%EC%9D%98-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8-%EC%88%98%EB%A3%8C%EC%A6%9D</guid>
            <pubDate>Thu, 25 Apr 2024 21:11:18 GMT</pubDate>
            <description><![CDATA[<h3 id="스프링-핵심-원리---기본편-수료증-및-후기">스프링 핵심 원리 - 기본편 수료증 및 후기</h3>
<p>지금부터 내가 수강한 강의 중 수료증이 발급된다면 업로드할 예정이다. 이 강의는 2021년도 개발을 처음 시작하였을 때 들었지만, 당시에는 이해를 하나도 못했다. 그래서 지금 2024년에 재수강하여 최근에 완강하였다. </p>
<p>강의에 대한 후기는, 해당 로드맵의 <strong>스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술</strong> 라는 첫번째 무료강의에 대한 연장선상으로 스프링에 대한 기본적인 원리에 대한 강의였다. 그래서 첫번째 무료 강의를 듣는 것을 추천하며, 무료강의 또한 퀄리티가 좋았다. </p>
<p>강의를 꽤 꼼꼼하게 듣는 편이라 강의노트도 잘 활용한다. 그래서 적어둔 노트를 보면서 블로그에 내 방식으로 정리를 하고 있다. 김영한 강사님을 너무 좋아해서 인프런에 올려주신 로드맵에 대한 강의를 모두 구매해버렸다. 올해 다 듣는게 목표인데, 너무 꼼꼼하게 들어서 가능할지는 모르겠다. </p>
<p>나는 스프링 프레임워크를 사용하면서도 왜 사용하는지 원리에 대해서 전혀 알지 못했다. 하지만 개발을 한지 2년이 조금 넘어서야, 느리더라도 깊은 공부를 해야겠다는 것을 정말 실감한다. 나와 같은 니즈를 느끼는 사람들에게 정말 적합한 강의를 선보이고 계시는 것 같아서 열성팬이 되어버렸다. </p>
<p>로드맵을 추천해주신 직장 동료분에게 감사하다. 앞으로도 느리지만 완강하여 수료증을 보면서 보람을 느끼고 싶다. 
<img src="https://velog.velcdn.com/images/honguniverse_dev/post/acc2fb4f-be6d-4a17-b1af-f944408263b6/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 스프링 컨테이너]]></title>
            <link>https://velog.io/@honguniverse_dev/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</link>
            <guid>https://velog.io/@honguniverse_dev/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</guid>
            <pubDate>Sun, 21 Apr 2024 06:02:06 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>스프링 컨테이너(Spring Container)</strong></p>
</blockquote>
<p>스프링 컨테이너는 자바 객체, 빈(Bean)의 생명 주기를 관리하며, 생성된 빈에게 추가적인 기능을 제공하는 것이다.</p>
<h4 id="✏️-스프링-컨테이너-생성">✏️ 스프링 컨테이너 생성</h4>
<p>AppConfig.class</p>
<pre><code class="language-java">@Configuration
public class AppConfig {
    @Bean
    public MemberService memberService(){
        return new MemberServiceImpl(memberRepository());
    }

    @Bean
    public OrderService orderService(){
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

    //중복을 방지하고, 역할과 구현 클래를 한 눈에 구분할 수 있다.
    @Bean
    public  MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }

    @Bean
    public DiscountPolicy discountPolicy() {
        //return new FixDiscountPolicy();

        //할인 정책이 바뀌었다.
        return new RateDiscountPolicy();
    }
}</code></pre>
<p><img src="https://velog.velcdn.com/images/honguniverse_dev/post/21129074-0b6c-47f4-9f4e-ac7e4da69050/image.png" alt=""></p>
<ul>
<li>그림과 같이 빈 이름은 메서드 이름을 사용한다. </li>
<li><code>@Bean(name=&quot;myBean&quot;)</code> 과 같이 빈 이름을 직접 부여할 수도 있지만, 빈 이름은 항상 다른 이름을 부여해야 한다. </li>
</ul>
<h4 id="✏️-스프링-빈-조회">✏️ 스프링 빈 조회</h4>
<p>스프링 컨테이너에 실제로 스프링 빈이 잘 등록되었는지 확인해보자.</p>
<pre><code class="language-java">ApplicationContext applicationContext =
                     new AnnotationConfigApplicationContext(AppConfig.class);</code></pre>
<ul>
<li><code>ApplicationContext</code> 인터페이스를 스프링 컨테이너라 하며 <code>AnnotationConfigApplicationContext</code>는 스프링 컨테이너 인터페이스의 구현체이다. </li>
</ul>
<p><img src="https://velog.velcdn.com/images/honguniverse_dev/post/054c04d3-4c36-4f2d-a3bc-d996487bab71/image.png" alt=""></p>
<p>BeanFactory는 스프링 컨테이너의 최상위 인터페이스로 빈을 관리하고 조회하는 역할을 담당하며 <code>getBean()</code> 을 제공한다.</p>
<ul>
<li>ApplicationContext는 기능을 상속받아 빈 관리기능 + 편리한 부가 기능을 제공한다. 모두 스프링 컨테이너라 한다.</li>
<li>ApplicationContext가 제공하는 부가기능에는 메시지소스를 이용한 국제화 기능, 환경변수, 이벤트, 리소스 조회가 있다. </li>
</ul>
<p>스프링 빈을 찾는 기본적인 조회 방법으로 다음과 같이 있다.</p>
<ul>
<li><code>ac.getBean(빈이름, 타입)</code></li>
<li><code>ac.getBean(타입)</code></li>
</ul>
<p>이를 활용하여 빈을 조회하는 테스트 코드를 작성하였다.</p>
<pre><code class="language-java">public class ApplicationContextBasicFindTest {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

    @Test
    @DisplayName(&quot;빈 이름으로 조회&quot;)
    void findBeanByName(){
        MemberService memberService = ac.getBean(&quot;memberService&quot;, MemberService.class);
        System.out.println(&quot;memberService = &quot; + memberService);
        System.out.println(&quot;memberService.getClass() = &quot; + memberService.getClass());
        assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
    }
    @Test
    @DisplayName(&quot;이름 없이 타입으로만 조회&quot;)
    void findBeanByType(){
        MemberService memberService = ac.getBean(MemberService.class);
        assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
    }
    @Test
    @DisplayName(&quot;구체 타입으로 조회&quot;)
    void findBeanByName2(){
        // 구현체로 확인하면 유연성이 떨어지지만 필요한 경우도 있음
        MemberService memberService = ac.getBean(&quot;memberService&quot;, MemberServiceImpl.class);
        assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
    }

    @Test
    @DisplayName(&quot;빈 이름으로 조회X&quot;)
    void findBeanByNameX(){
        //MemberService memberService = ac.getBean(&quot;xxxxx&quot;, MemberServiceImpl.class);
        // ()-&gt; 뒤의 로직 실행시, 다음과 같은 Exception 발생하는지에 대한 확인
        assertThrows(NoSuchBeanDefinitionException.class,
                        () -&gt; ac.getBean(&quot;xxxxx&quot;, MemberServiceImpl.class));
    }
}</code></pre>
<p>마지막 테스트는 조회 빈이 없는 경우 <code>NoSuchBeanDefinitionException</code> 예외 발생을 확인한 것이다.</p>
<hr>
<br>


<p><em>이 게시물은 인프런 김영한 강사의 <code>스프링 핵심 원리 - 기본편</code> 을 듣고 작성하였습니다.</em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[(스프링) IoC, DI, 컨테이너]]></title>
            <link>https://velog.io/@honguniverse_dev/%EC%8A%A4%ED%94%84%EB%A7%81-IoC-DI-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</link>
            <guid>https://velog.io/@honguniverse_dev/%EC%8A%A4%ED%94%84%EB%A7%81-IoC-DI-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</guid>
            <pubDate>Fri, 19 Apr 2024 23:35:33 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>제어의 역전 IoC(Inversion of Control)</strong></p>
</blockquote>
<p>: 쉽게 말하면 Config 클래스가 <strong>프로그램에 대한 제어 흐름을 가져가는 것</strong>이다. 예를들어 Impl 클래스가 직접 로직을 수행하지만 호출하는 인터페이스의 어떤 구현 객체를 실행시킬지 제어하는 것이다. </p>
<p>이렇듯 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것을 제어의 역전(IoC)라고 하며, 이는 객체지향 설계의 5가지 원칙 중 대표적으로 SRP, DIP, OCP를 지키기 위함이다. </p>
<hr>
<p>✏️** SRP 단일 책임 원칙**
: 한 클래스는 하나의 책임만 가져야 한다.</p>
<ul>
<li>구현 객체를 생성하고 연결하는 책임은 Config가 담당</li>
<li>클라이언트 객체(ex Impl클래스)는 실행하는 책임만 담당</li>
<li>SRP 단일 책임 원칙을 따르면서 관심사를 분리함</li>
</ul>
<p><strong>[역할과 구현의 분리]</strong>
: 역할과 구현으로 구분하면 세상이 단순, 유연해지며 변경도 편리해진다.</p>
<p>클라이언트는 대상의 역할만 알면 된다.
클라이언트는 구현 대상의 내부 구조를 몰라도 된다.
클라이언트는 구현 대상의 내부 구조가 변경되어도, 대상 자체를 변경해도 영향 받지 않는다.</p>
<p>자바에서도 이런 특징을 활용한다.</p>
<ul>
<li>역할 = 인터페이스</li>
<li>구현 = 인터페이스를 구현한 클래스, 구현 객체</li>
</ul>
<p>객체를 설계할 때 역할과 구현을 명확히 분리한다. 객체를 설계할 때 역할(인터페이스)를 먼저 부여하고, 그 역할을 수행하는 구현 객체를 만든다.</p>
<p>✏️** DIP 의존관계 역전 원칙**
: <strong>추상화가 아닌 구체화에 의존하면 안된다. 의존성 주입은 이 원칙을 따르는 방법 중 하나이다.</strong></p>
<pre><code class="language-java">public class OrderServiceImpl implements OrderService {
 //  DiscountPolicy 인터페이스의 구현객체 변경으로 코드 수정해야함. Fix =&gt; Rate
 //  private final DiscountPolicy discountPolicy = new FixDiscountPolicy();

     private final DiscountPolicy discountPolicy = new RateDiscountPolicy();
 }</code></pre>
<p>이는 추상(인터페이스) 뿐만 아니라 <strong>구체(구현) 클래스에도 의존</strong>하고 있다. 따라서 DIP위반, 변경해야 하기 때문에 OCP 모두 위반한다. 인터페이스에만 의존하도록 변경하면 아래와 같다.</p>
<p>애플리케이션의 전체 동작 방식을 구성(config)하기 위해, <strong>구현 객체를 생성</strong>하고, <strong>연결</strong>하는 책임을 가지는 별도의 설정 Config 클래스를 만든 뒤, 생성자 주입을 사용한다. 
빈 Bean 활용을 통한 설정은 아래에 추가적으로 소개하고, 순수 코드로 작성하였다.</p>
<pre><code class="language-java">public class AppConfig {
     //FixDiscountPolicy 구현체 사용
     public OrderService orderService() {
         return new OrderServiceImpl(new FixDiscountPolicy());
     }
}</code></pre>
<pre><code class="language-java">public class OrderServiceImpl implements OrderService {
     private final DiscountPolicy discountPolicy;

     public OrderServiceImpl(DiscountPolicy discountPolicy) {
         this.memberRepository = memberRepository;
         this.discountPolicy = discountPolicy;
     }
}</code></pre>
<p>AppConfig가 <code>FixDiscountPolicy</code> 객체 인스턴스를 클라이언트 코드 대신 생성해서 클라이언트 코드에 의 존관계를 주입했다. 이렇게해서 DIP 원칙을 따르면서 문제도 해결했다.</p>
<p>✏️** OCP 개방 폐쇄의 원칙**
: <strong>소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다</strong></p>
<ul>
<li>다형성을 사용하고 클라이언트가 DIP를 지킨다.</li>
<li>애플리케이션을 사용 영역과 구성 영역으로 나눈다.</li>
<li>위의 예시에서 AppConfig가 의존관계를 <code>FixDiscountPolicy</code> <code>RateDiscountPolicy</code> 로변경해서 클라이언트코드에 주입하므로 클라이언트 코드는 변경하지 않아도 되므로, <strong>소프트웨어 요소를 새롭게 확장해도 사용 영역의 변경은 닫혀 있다!</strong></li>
</ul>
<hr>
<blockquote>
<p><strong>의존관계 주입 DI(Dependency Injection)</strong></p>
</blockquote>
<p>: 의존관계는 <strong>정적인 클래스 의존 관계와, 실행 시점에 결정되는 동적인 객체(인스턴스) 의존 관계</strong> 둘을 분리해서 생각해야 한다.</p>
<p>✏️** 정적인 클래스 의존관계**
클래스가 사용하는 import 코드만 보고 의존관계를 쉽게 판단할 수 있다. 정적인 의존관계는 애플리케이션을 실행하지 않아도 분석할 수 있다. 그러나 이러한 클래스 의존관계 만으로는 실제 어떤 객체가 주입될지 알 수 없다.</p>
<p>✏️ <strong>동적인 객체 인스턴스 의존관계</strong>
: 애플리케이션 실행 시점에 실제 생성된 객체 인스턴스의 참조가 연결된 의존 관계다.</p>
<p>애플리케이션 실행 시점(런타임)에 외부에서 실제 구현 객체를 생성하고 그 참조값을 전달해서 연결하는데, 이렇게 클라이언트에 전달해서 서버와 실제 의존관계가 연결되는 것을 <code>의존관계 주입</code>이라 한다.
<strong>즉, 의존관계 주입을 사용하면 정적인 클래스 의존관계를 변경하지 않고, 동적인 객체 인스턴스 의존관계를 쉽게 변경 할 수 있다.</strong></p>
<hr>
<blockquote>
<p><strong>DI 컨테이너 (IoC 컨테이너)</strong></p>
</blockquote>
<p>: Config 설정 클래스처럼 객체를 생성하고 관리하면서 의존관계를 연결해주는 것을 <code>DI 컨테이너</code>라고 한다. 또는 어샘블러, 오브젝트 팩토리 등으로 불리기도 한다.</p>
<p><strong>[스프링으로 전환하기]</strong>
위에서는 순수한 자바 코드만으로 DI를 적용했다. 스프링을 사용하면 다음과 같이 수정할 수 있다. 아래와 같이 하면 스프링 컨테이너에 스프링 빈으로 등록한다.</p>
<pre><code class="language-java">@Configuration
public class AppConfig {

    @Bean
    public OrderService orderService() {
        return new OrderServiceImpl(discountPolicy());
    }

    @Bean
    public DiscountPolicy discountPolicy() {
        return new RateDiscountPolicy();
    }
}</code></pre>
<ul>
<li>스프링 컨테이너는 <code>@Configuration</code> 이 붙은 <code>AppConfig</code> 를 설정(구성) 정보로 사용한다. 여기서 <code>@Bean</code> 이 라 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록하며, 이를 <strong>스프링 빈</strong>이라 한다.</li>
<li>스프링 빈은 <code>@Bean</code> 이 붙은 메서드의 명을 스프링 빈의 이름으로 사용한다. 스프링 컨테이너에 객체를 스프링 빈으로 등록 하고, 스프링 빈을 찾아서 사용할 수 있다.</li>
</ul>
<hr>
<p>📍 스프링 컨테이너를 통 해서 필요한 스프링 빈(객체)를 찾는 법</p>
<pre><code class="language-java">ApplicationContext applicationContext 
        = new AnnotationConfigApplicationContext(AppConfig.class);

OrderService orderService = applicationContext.getBean(&quot;orderService&quot;, OrderService.class);
</code></pre>
<p><code>ApplicationContext</code> 를 스프링 컨테이너라 하며, <code>applicationContext.getBean()</code> 메서드를 사용 해서 찾을 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[HashMap 동시성 이슈]]></title>
            <link>https://velog.io/@honguniverse_dev/HashMap-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%9D%B4%EC%8A%88</link>
            <guid>https://velog.io/@honguniverse_dev/HashMap-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%9D%B4%EC%8A%88</guid>
            <pubDate>Sat, 13 Apr 2024 07:00:08 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>동시성 이슈</p>
</blockquote>
<p>스레드는 cpu 작업의 한단위이다. 멀티스레드 방식은 멀티태스킹을 하는 방식 중, 한 코어에서 여러 스레드를 이용해서 <strong>번갈아 작업을 처리하는 방식</strong>이다.</p>
<p>멀티 스레드를 이용하면 공유하는 영역이 많아 프로세스방식보다 context switcing(작업전환) 오버헤드가 작아, 메모리 리소스가 상대적으로 적다는 장점이 있다.</p>
<p><em>(프로세스는 운영체제로부터 자원을 할당받은 작업의 단위이며, 스레드는 프로세스가 할당받은 자원을 이용하는 실행 흐름의 단위이다.)</em></p>
<p>하지만 자원을 공유해서 단점도 존재한다.
그게 바로, 동시성(concurrency) 이슈이다.</p>
<p>여러 스레드가 동시에 하나의 자원을 공유하고 있기 때문에 같은 자원을 두고 경쟁상태(raceCondition) 같은 문제가 발생하는 것이다.</p>
<blockquote>
<p>HashMap vs ConcurrentHashMap</p>
</blockquote>
<p>HashMap은 내부에서 동기화를 제공하지 않기 때문에 단일 스레드(single-threaded) 애플리케이션에 적합하다.</p>
<p>ConcurrentHashMap은 내부에서 동기화(synchronization)를 제공하여 여러 개의 스레드가 동시에 맵에 접근하고 수정할 수 있도록 하기 때문에 동시 다중 스레드(concurrent multi-threaded) 애플리케이션에 적합하다.</p>
<blockquote>
<p>Java의 동시성 문제</p>
</blockquote>
<p>Java는 멀티 스레드 프로그래밍이 가능한 언어입니다. JVM은 보통 어떤 서버(기기) 상에서 실행되고 있는 프로세스를 말합니다. 이러한 JVM은 최소 한 개(main 스레드) 이상 여러 스레드를 가질 수 있습니다.</p>
<p>그렇다면 많은 스레드가 공유한 자원에 동시에 접근하게 되면 어떤 문제가 발생할 수 있을까요?</p>
<pre><code class="language-java">public class Main {

    public static void main(String[] args) {
        Counter counter = new Counter();

        Thread thread1 = new Thread(() -&gt; {
            for (int i = 0; i &lt; 10000; i++) {
                counter.increment();
            }
        });

        Thread thread2 = new Thread(() -&gt; {
            for (int i = 0; i &lt; 10000; i++) {
                counter.increment();
            }
        });

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

        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(&quot;Final Counter Value: &quot; + counter.getCount());
    }

    public static class Counter {
        private int count = 0;

        public void increment() {
            count++;
        }

        public int getCount() {
            return count;
        }
    }
}</code></pre>
<p>위 코드만 간단하게 본다면, 정상적으로 동작했을 경우 count의 수는 20000이 되어야 합니다. 실제 코드를 실행하고 결과를 확인 하면 아래와 같습니다.</p>
<pre><code>Final Counter Value: 16950</code></pre><p>매 실행마다 다른 결과값을 받아 볼 수 있습니다. 그 이유는 Java의 특성인 멀티 스레드 프로그래밍에 있습니다. 두 스레드가 하나의 자원에 동시에 접근하며, 동기화 되지 않은 데이터의 결과입니다.</p>
<hr>
<h4 id="참고">참고</h4>
<p><a href="https://velog.io/@twinsgemini/%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%9D%B4%EC%8A%88-HashMap-vs-ConcurrentHashMap">[동시성 이슈] HashMap vs ConcurrentHashMap</a>
<a href="https://velog.io/@mooh2jj/%EB%A9%80%ED%8B%B0-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EB%8F%99%EC%8B%9C%EC%84%B1-%EC%9D%B4%EC%8A%88">[Java] 멀티 스레드환경의 동시성 이슈 그리고 해결방법</a>
<a href="https://devlog-wjdrbs96.tistory.com/269">[Java] ConcurrentHashMap 이란 무엇일까?</a>
<a href="https://inpa.tistory.com/entry/%F0%9F%91%A9%E2%80%8D%F0%9F%92%BB-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%E2%9A%94%EF%B8%8F-%EC%93%B0%EB%A0%88%EB%93%9C-%EC%B0%A8%EC%9D%B4">완전히 정복하는 프로세스 vs 스레드 개념</a>
<a href="https://velog.io/@akfls221/%EB%8F%99%EC%8B%9C%EC%84%B1%EC%97%90-%EB%8C%80%ED%95%9C-%ED%95%B4%EA%B2%B0%EB%B0%A9%EB%B2%95%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90">동시성에 대한 해결방법을 알아보자</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[java file outside of source root 오류 해결법]]></title>
            <link>https://velog.io/@honguniverse_dev/java-file-outside-of-source-root-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0%EB%B2%95</link>
            <guid>https://velog.io/@honguniverse_dev/java-file-outside-of-source-root-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0%EB%B2%95</guid>
            <pubDate>Sun, 07 Apr 2024 21:33:14 GMT</pubDate>
            <description><![CDATA[<p>1) 인텔리제이 기준 View - Tool Windows - Gradle
또는 우측의 Gradle 클릭하여 Refresh Gradle Dependencies를 한다.
<img src="https://velog.velcdn.com/images/honguniverse_dev/post/e4c1db2d-7fa6-4a88-a6e6-72cac85bd71e/image.png" alt=""></p>
<p>2) Java 폴더를 우클릭하여 Mark directory as를 통해 source root로 설정한다.
<img src="https://velog.velcdn.com/images/honguniverse_dev/post/794214a7-33db-4b50-a67f-65d4a1f5cf0c/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[동기(Synchronous), 비동기(Asynchronous)]]></title>
            <link>https://velog.io/@honguniverse_dev/%EB%8F%99%EA%B8%B0Synchronous-%EB%B9%84%EB%8F%99%EA%B8%B0Asynchronous</link>
            <guid>https://velog.io/@honguniverse_dev/%EB%8F%99%EA%B8%B0Synchronous-%EB%B9%84%EB%8F%99%EA%B8%B0Asynchronous</guid>
            <pubDate>Sun, 17 Mar 2024 02:09:59 GMT</pubDate>
            <description><![CDATA[<h3 id="동기-vs-비동기"><strong>동기 VS 비동기</strong></h3>
<p>동기는 요청한 작업에 대해 완료 여부를 따져 <strong>순차대로</strong> 처리한다.</p>
<p>비동기는 동시에 일어나지 않는다는 의미로 요청한 작업에 대해 완료 여부를 따지지 않기 때문에 <strong>자신의 다음 작업을 그대로 수행</strong>한다.
<img src="https://velog.velcdn.com/images/honguniverse_dev/post/40736255-8bdf-48fa-b0c7-3b117e8b30af/image.png" alt=""></p>
<blockquote>
<p><strong>블록(Blocking) / 논블록(Non-Blocking)</strong></p>
</blockquote>
<p>동기/비동기가 전체적인 작업에 대한 순차적인 흐름 유무라면, 블로킹/논블로킹은 전체적인 작업의 흐름 자체를 막냐 안 막냐로 볼 수 있다. </p>
<p>논블록킹을 방식은 어떤 작업을 실행하여도 대기하지 않고 다른 작업을 할 수 있다. 비동기와 비슷해보이는데, 두 개념이 조합되어 사용된다.</p>
<ul>
<li>Sync Blocking (동기 + 블로킹)</li>
<li>Async Blocking (비동기 + 블로킹)</li>
<li>Sync Non-Blocking (동기 + 논블로킹) </li>
<li>Async Non-Blocking (비동기 + 논블로킹)</li>
</ul>
<hr>
<p>✏️ 다음
#1. 동기, 비동기, 블록, 논블록 네가지 조합에 대한 설명
#2. 큐, 스택 자료구조 
#3. 프로세스, 스레드 개념과 멀티 프로세스, 멀티 스레드로 확장
#4. 자바스크립트의 동작원리</p>
<hr>
<p>📄 참고
<a href="https://inpa.tistory.com/entry/%F0%9F%91%A9%E2%80%8D%F0%9F%92%BB-%EB%8F%99%EA%B8%B0%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%B8%94%EB%A1%9C%ED%82%B9%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC#%EB%8F%99%EA%B8%B0/%EB%B9%84%EB%8F%99%EA%B8%B0_+_%EB%B8%94%EB%A1%9C%ED%82%B9/%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9_%EC%A1%B0%ED%95%A9">완벽히 이해하는 동기/비동기 &amp; 블로킹/논블로킹</a>
<a href="https://inpa.tistory.com/entry/%F0%9F%91%A9%E2%80%8D%F0%9F%92%BB-multi-process-multi-thread">멀티 프로세스 vs 멀티 스레드 비교 💯 완전 총정리</a>
<a href="https://inpa.tistory.com/entry/%F0%9F%94%84-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%9D%B4%EB%B2%A4%ED%8A%B8-%EB%A3%A8%ED%94%84-%EA%B5%AC%EC%A1%B0-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC">자바스크립트 이벤트 루프 동작 구조 &amp; 원리 끝판왕</a>
<a href="https://ljtaek2.tistory.com/m/142">자바스크립트 동기, 비동기?</a></p>
]]></description>
        </item>
    </channel>
</rss>