ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java μ‘μš©] 11. μŠ€λ ˆλ“œ(Thread)λ₯Ό μ‚¬μš©ν•œ 병렬 처리
    Dev/Java 2023. 3. 26. 23:45
    728x90

    πŸ‘€ μœ μš©ν•œ 정보

    eclipse μ—μ„œ μ½”λ“œ 계측 ꡬ쑰 보기

    • f3 ν•΄λ‹Ή νƒ€κ²ŸμœΌλ‘œ κ°€κΈ° β†’ 우클릭 β†’ Open Call Hierarchy

    πŸ’‘ν”Όλ“œλ°± Tip

    ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ˜ μž₯점

    πŸ’‘
    기쑴의 if, forλ¬Έ κ°œλ°œμžκ°€ μ‹€μˆ˜ν•  수 μžˆλŠ” μš”μ†Œλ“€μ΄ λ§Žμ•˜λ‹€. (좔가적인 λ³€μˆ˜ μ‚¬μš©, 쑰건, λΆ„κΈ° μ œμ–΄ λ“±) Stream을 μ‚¬μš©ν•œ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ€ 좔가적인 λ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šμ•„λ„ μ²˜λ¦¬κ°€ λœλ‹€. λ”°λΌμ„œ, 개발자의 μ‹€μˆ˜λ₯Ό 쀄일 수 μžˆλ‹€.

    Lambda의 μΆ•μ•½

    πŸ’‘
    μ½”λ“œμ˜ 가독성을 μœ„ν•΄ Lambda 식을 μ‚¬μš©ν•  λ•Œ 좕약이 κ°€λŠ₯ν•  λ•Œμ—λ„ νƒ€μž… 등을 λͺ…μ‹œν•΄λ‘λŠ” 것이 μ’‹λ‹€.

    μ†Œν”„νŠΈμ›¨μ–΄ ν…ŒμŠ€νŠΈμ˜ μ£Όμš” μ ‘κ·Ό 방식

    1. ν™”μ΄νŠΈ λ°•μŠ€ ν…ŒμŠ€νŠΈ

    πŸ’‘
    White Box Testing은 μ†Œν”„νŠΈμ›¨μ–΄μ˜ λ‚΄λΆ€ ꡬ쑰와 μ½”λ“œλ₯Ό λΆ„μ„ν•˜μ—¬ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό μ„€κ³„ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€. μ†Œν”„νŠΈμ›¨μ–΄μ˜ λ‚΄λΆ€ λ™μž‘μ„ μ΄ν•΄ν•˜κ³  ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό 보닀 효율적으둜 섀계할 수 μžˆμ§€λ§Œ, μ†Œν”„νŠΈμ›¨μ–΄μ˜ λ‚΄λΆ€ ꡬ쑰λ₯Ό μ΄ν•΄ν•˜κΈ° μœ„ν•΄ κ°œλ°œμžλ‚˜ 기술적인 λŠ₯λ ₯이 μš”κ΅¬λœλ‹€.

    πŸ‘€ μ‘μš©Ch10의 클래슀 JUnit λ‹¨μœ„ ν…ŒμŠ€νŠΈλŠ” ν™”μ΄νŠΈ λ°•μŠ€ ν…ŒμŠ€νŠΈλΌ λ³Ό 수 μžˆλ‹€.

    2. λΈ”λž™ λ°•μŠ€ ν…ŒμŠ€νŠΈ

    πŸ’‘
    Black Box Testing은 μ†Œν”„νŠΈμ›¨μ–΄μ˜ λ‚΄λΆ€ κ΅¬μ‘°λ‚˜ μ½”λ“œλ₯Ό κ³ λ €ν•˜μ§€ μ•Šκ³ , μ†Œν”„νŠΈμ›¨μ–΄μ˜ μž…λ ₯κ³Ό 좜λ ₯λ§Œμ„ κ²€μ¦ν•˜μ—¬ ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό μ„€κ³„ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€. 이 방식은 μ†Œν”„νŠΈμ›¨μ–΄μ˜ κΈ°λŠ₯을 μ€‘μ‹¬μœΌλ‘œ ν…ŒμŠ€νŠΈλ₯Ό μˆ˜ν–‰ν•˜λ―€λ‘œ 비전문가도 ν…ŒμŠ€νŠΈλ₯Ό μˆ˜ν–‰ν•  수 있으며, μ†Œν”„νŠΈμ›¨μ–΄μ˜ μ™ΈλΆ€ μ‚¬μš©μž κ΄€μ μ—μ„œ 검증할 수 μžˆμŠ΅λ‹ˆλ‹€.

    πŸ‘€ ν”„λ‘œκ·Έλž¨ λ°–μ—μ„œ μž…μΆœλ ₯ λ§Œμ„ κ²€μ‚¬ν•œλ‹€.

    컀버리지

    πŸ’‘
    μ†Œν”„νŠΈμ›¨μ–΄ ν…ŒμŠ€νŠΈμ—μ„œ μ‚¬μš©λ˜λŠ” μ§€ν‘œ 쀑 ν•˜λ‚˜λ‘œ, μ†Œν”„νŠΈμ›¨μ–΄ μ½”λ“œμ˜ μ–΄λŠ 정도가 ν…ŒμŠ€νŠΈλ˜μ—ˆλŠ”μ§€λ₯Ό λ‚˜νƒ€λ‚Έλ‹€.

    ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€κ°€ μ‹€ν–‰λœ 후에 μ–Όλ§ˆλ‚˜ λ§Žμ€ μ½”λ“œκ°€ μ‹€ν–‰λ˜μ—ˆλŠ”μ§€λ₯Ό κ³„μ‚°ν•˜μ—¬ λ‚˜νƒ€λ‚Έλ‹€. ex) 100μ€„μ˜ μ½”λ“œ 쀑 80쀄이 μ‹€ν–‰λ˜μ—ˆλ‹€λ©΄, μ½”λ“œ μ»€λ²„λ¦¬μ§€λŠ” 80%이닀.

    πŸ’‘
    μ‘μš©Ch10μ—μ„œ μž‘μ„±ν•œ ν…ŒμŠ€νŠΈ μ½”λ“œμ˜ Coverage ν™•μΈν•΄λ³΄λ‹ˆ, BankTestλŠ” 82%의 컀버리지λ₯Ό λ³΄μ˜€λ‹€.


    πŸ“˜ μ‘μš© 11μž₯ μŠ€λ ˆλ“œ(Thread)λ₯Ό μ‚¬μš©ν•œ 병렬 처리

    μŠ€λ ˆλ“œ (Thread)

    • μŠ€λ ˆλ“œ(Thread) : ν”„λ‘œμ„ΈμŠ€ λ‚΄μ—μ„œ μ‹€ν–‰λ˜λŠ” νλ¦„μ˜ λ‹¨μœ„
    πŸ’‘
    JavaλŠ” λ™μ‹œμ— 2κ°€μ§€ μ΄μƒμ˜ λͺ…령을 λ™μ‹œμ— μˆ˜ν–‰ν•˜κΈ° μœ„ν•΄ Thread APIλ₯Ό μ œκ³΅ν•œλ‹€.

    기쑴의 μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šμ€ 좜λ ₯ 예

    for (int i = 0; i < 10; i++) {
    		System.out.println(i);
    }

    μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 예

    πŸ’‘
    run() λ©”μ„œλ“œλ₯Ό κ°€μ§„ Runnable μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ PrintingThread 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό Thread 객체에 인자둜 μ£Όμ–΄ μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.
    package com.pkd.example;
    
    public class PrintingThread implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println(i);
            }
        }
    }
    package com.pkd.example;
    
    import java.util.Scanner;
    
    public class Main {
    
        public static void main(String[] args) {
            System.out.println("μ•„λ¬΄κ±°λ‚˜ μž…λ ₯");
            Scanner sc = new Scanner(System.in);
    
            Thread thread = new Thread(new PrintingThread());
            thread.start();
            sc.nextLine();
    		}
    }

    πŸ’‘
    μŠ€λ ˆλ“œ κ΅¬ν˜„μ€ λ‹€μ–‘ν•œ λ°©μ‹μœΌλ‘œ κ΅¬ν˜„ν•  수 μžˆλ‹€. μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μ„ μ‚¬μš©ν•  λ•Œ λ‹€ν˜•μ„±μ„ μ΄μš©ν•˜λ©΄ μ—¬λŸ¬κ°€μ§€ ν˜•νƒœλ‘œ κ΅¬ν˜„ν•  수 μžˆλ‹€. ex) 무λͺ… 클래슀, λžŒλ‹€μ‹ 이용 λ“±
    package com.pkd.example;
    
    public class Main {
    
        public static void main(String[] args) {
            // Runnable κ΅¬ν˜„ν•œ 클래슀λ₯Ό 인자둜 μ£Όμ–΄ μŠ€λ ˆλ“œ μ‚¬μš©
            Thread thread = new Thread(new PrintingThread());
            thread.start();
            
             // 무λͺ… 클래슀λ₯Ό ν™œμš©ν•œ μŠ€λ ˆλ“œ κ΅¬ν˜„
             new Thread(new Runnable() {
             @Override
             public void run() {}
             }).start();
            
            
             // λžŒλ‹€μ‹μ„ μ΄μš©ν•œ μŠ€λ ˆλ“œ κ΅¬ν˜„
             new Thread(() -> {
            
             }).start();
    πŸ’‘
    무λͺ… 클래슀, λžŒλ‹€μ‹ μƒν˜Έ μ½”λ“œ λ³€ν™˜ κΏ€νŒ! - κ΅¬ν˜„λœ 무λͺ… 클래슀 β†’ Ctrl + 1 : Convert to lambda expression - κ΅¬ν˜„λœ λžŒλ‹€μ‹ β†’ Ctrl + 1 : Convert to lambda Class

    μŠ€λ ˆλ“œ 확인해보기

    package com.pkd.example;
    
    import java.util.Scanner;
    
    public class Main {
    
        public static void main(String[] args) {
            StringBuffer sb = new StringBuffer();
            
            new Thread(() -> {
                for (int i = 0; i < 5; i++)
                    try {
                        Thread.sleep(100);
                        System.out.println("Thread :" + Thread.currentThread().getName() + " " + i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
            }).start();
    
    
            new Thread(() -> {
                for (int i = 0; i < 5; i++)
                    try {
                        Thread.sleep(100);
                        System.out.println("Thread :" + Thread.currentThread().getName() + " " + i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
            }).start();
        }
    }

    πŸ’‘
    μŠ€λ ˆλ“œλ₯Ό 좜λ ₯ ν•΄λ³΄λ‹ˆ, λΆˆκ·œμΉ™ν•œ μˆœμ„œλŒ€λ‘œ μŠ€λ ˆλ“œκ°€ μ‹€ν–‰λ˜λŠ” 것을 λ³Ό 수 μžˆλ‹€.

    μŠ€λ ˆλ“œ μ„Έμ΄ν”„ν•œ 섀계

    πŸ’‘
    볡수의 μŠ€λ ˆλ“œλ₯Ό μ΄μš©ν•œ ν”„λ‘œκ·Έλž˜λ°μ„ λ©€ν‹°μŠ€λ ˆλ“œ ν”„λ‘œκ·Έλž˜λ° 이라고 ν•œλ‹€.

    μˆœμ„œλŒ€λ‘œ μ‹€ν–‰λ˜λŠ” 것을 동기(Synchronization) 이라고 ν•˜κ³  μ—¬λŸ¬ μŠ€λ ˆλ“œκ°€ λ™μ‹œμ— λ³‘λ ¬λ‘œ μ‹€ν–‰λ˜λŠ” 것을 비동기(Asynchronization) 이라고 ν•œλ‹€ .

    Javaμ—λŠ” μ—¬λŸ¬ μŠ€λ ˆλ“œλ₯Ό μ œμ–΄ν•˜λŠ” 방법을 μ œκ³΅ν•˜κ³  β€˜μ—¬λŸ¬ μŠ€λ ˆλ“œμ—μ„œ λ™μ‹œμ— μ΄μš©ν•΄λ„ μ•ˆμ „ν•œ ν΄λž˜μŠ€λ‚˜ λ©”μ„œλ“œ'λŠ” μŠ€λ ˆλ“œ 세이프 (Thread safe)ν•œ 섀계라고 말할 수 μžˆλ‹€.

    1000개의 μŠ€λ ˆλ“œμ˜ κ²½ν•© 쑰건(race condition) 문제 λ°œμƒ

    package com.pkd.example;
    
    public class Counter {
        int num = 0;
    
        public static void main(String[] args) throws Exception {
            Counter counter = new Counter();
            // 1. 동기화λ₯Ό ν•˜μ§€ μ•Šμ•˜μ„ 경우.
            for (int i = 0; i < 1000; i++) {
                new Thread(() -> {
                     try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    counter.num++; // μŠ€λ ˆλ“œ λ‚΄μ—μ„œ λ‹€λ₯Έ 객체λ₯Ό μ‘°μž‘ν•˜λ©΄
                }).start();
            }
            Thread.sleep(2000);
            System.out.println(counter.num);
        }
    }
    πŸ’‘
    for λ£¨ν”„μ—μ„œ 1000개의 μŠ€λ ˆλ“œλ₯Ό μƒμ„±ν•˜μ—¬ μ‹€ν–‰ν•˜κ³ , 각 μŠ€λ ˆλ“œλŠ” 10λ°€λ¦¬μ΄ˆμ˜ λ”œλ ˆμ΄ 후에 num λ³€μˆ˜λ₯Ό μ¦κ°€μ‹œν‚¨λ‹€.

    μ΄λ•Œ, 10λ°€λ¦¬μ΄ˆ λ”œλ ˆμ΄κ°€ λͺ¨λ“  μŠ€λ ˆλ“œμ— λŒ€ν•΄ μΆ©λΆ„ν•˜μ§€ μ•Šμ„ 수 μžˆλ‹€. λ”°λΌμ„œ, μŠ€λ ˆλ“œλ“€μ΄ num λ³€μˆ˜λ₯Ό λ™μ‹œμ— μ¦κ°€μ‹œν‚€λŠ” 것이 κ°€λŠ₯ν•˜λ©°, 이둜 인해 κ²½ν•© 쑰건(Race Condition) λ¬Έμ œκ°€ λ°œμƒν–ˆλ‹€. λ³€μˆ˜ 값이 순차적으둜 정상 증가 λ˜μ§€ μ•Šμ•˜μŒμ—λ„, 각 μŠ€λ ˆλ“œκ°€ λ™μ‹œμ— λ³€μˆ˜μ— μ ‘κ·Όν•˜κ²Œ λ˜μ–΄ μ›ν•˜λŠ” 값이 μ €μž₯λ˜μ§€ μ•Šμ€ λ¬Έμ œκ°€ λ°œμƒν•œ 것이닀.

    πŸ’‘
    λ”°λΌμ„œ, λ©€ν‹° μŠ€λ ˆλ“œμ˜ Race condition 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ 각 μŠ€λ ˆλ“œκ°€ ν•˜λ‚˜μ˜ μžμ›μ„ μ ‘κ·Όν•˜λŠ” 뢀뢄에 동기화 μ²˜λ¦¬κ°€ ν•„μš”ν•˜λ‹€.

    Synchronized에 μ˜ν•œ 동기화 μ œμ–΄

    πŸ’‘
    synchronized ν‚€μ›Œλ“œλ₯Ό ν™œμš©ν•œ λ³€μˆ˜ 접근에 λŒ€ν•œ lock 처리
    package com.pkd.example;
    
    public class Counter {
        int num = 0;
    
        public static void main(String[] args) throws Exception {
            // 2. 동기화 ν–ˆμ„ 경우
            Counter counter2 = new Counter();
            for (int i = 0; i < 1000; i++) {
                new Thread(() -> {
                    try {
                        Thread.sleep(10);
                        synchronized (counter2) {
                            counter2.num++; // μŠ€λ ˆλ“œ λ‚΄μ—μ„œ λ‹€λ₯Έ 객체λ₯Ό μ‘°μž‘ν•˜λ©΄
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }).start();
            }
            Thread.sleep(2000);
            System.out.println(counter2.num);
        }
    }
    πŸ’‘
    synchronized ν‚€μ›Œλ“œλ₯Ό ν™œμš©ν•΄ λ™μ‹œμ„±μ„ 보μž₯ν•˜κ²Œ λ˜μ–΄ κ²½ν•© 쑰건 문제λ₯Ό ν•΄κ²°ν•  수 μžˆμ—ˆλ‹€. λ”°λΌμ„œ, 볡수의 μŠ€λ ˆλ“œκ°€ μ‹€ν–‰ν•  수 μžˆλŠ” κ°€λŠ₯성이 μžˆλŠ” 뢀뢄은 synchronized 블둝 내에 μž‘μ„±ν•˜λ©΄ λœλ‹€.

    πŸ’‘
    1) λ©”μ„œλ“œ 선언뢀에 synchronized ν‚€μ›Œλ“œ μΆ”κ°€ 2) main()의 동기화가 ν•„μš”ν•œ 뢀뢄에 synchronized ν‚€μ›Œλ“œ μΆ”κ°€

    μŠ€λ ˆλ“œ μ‚¬μš©μ— μžˆμ–΄μ„œμ˜ μœ„ν—˜μ„± (κ΅μ°©μƒνƒœ)

    κ΅μ°©μƒνƒœ (DeadLock) μ˜ˆμ‹œ

    πŸ’‘
    κ΅μ°©μƒνƒœ μ‹œλ‚˜λ¦¬μ˜€ μ„€λͺ… thread1 synchronized둜 인해 resource1에 λŒ€ν•œ lock β†’ resource1이 κ°€μš©ν•  수 μžˆλŠ” μƒνƒœλΌλ©΄ ν•΄λ‹Ή resource1λ₯Ό μ μœ ν•˜κ³ , λ‹€λ₯Έ μŠ€λ ˆλ“œκ°€ resource1에 λŒ€ν•΄ μ ‘κ·Όν•˜μ§€ λͺ»ν•˜λ„둝 lock을 건닀. thread2 synchronized둜 인해 resource2에 λŒ€ν•œ lock β†’ resource2이 κ°€μš©ν•  수 μžˆλŠ” μƒνƒœλΌλ©΄ ν•΄λ‹Ή resource2λ₯Ό μ μœ ν•˜κ³ , λ‹€λ₯Έ μŠ€λ ˆλ“œκ°€ resource2에 λŒ€ν•΄ μ ‘κ·Όν•˜μ§€ λͺ»ν•˜λ„둝 lock을 건닀. thread1 β†’ resource2에 λŒ€ν•΄ μ μœ ν•˜μ§€ λͺ»ν•΄ λ¬΄ν•œμ • λŒ€κΈ° thread2 β†’ resource1에 λŒ€ν•΄ μ μœ ν•˜μ§€ λͺ»ν•΄ λ¬΄ν•œμ • λŒ€κΈ°
    πŸ’‘
    κ΅μ°©μƒνƒœμ— 빠져버렸닀.

    μŠ€λ ˆλ“œ μ‚¬μš©μ‹œ κ³ λ €ν•  점

    πŸ’‘
    μŠ€λ ˆλ“œλŠ” λ˜λ„λ‘ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 것이 μ’‹λ‹€.

    μ–΄μ©” 수 μ—†λŠ” κ²½μš°μ—λ§Œ μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•˜κ³ , 리슀크λ₯Ό κ°μˆ˜ν•  각였λ₯Ό ν•˜κ³ , κ°œλ°œκΈ°κ°„μ΄λ‚˜ ν…ŒμŠ€νŠΈμ— μΆ©λΆ„ν•œ μ‹œκ°„μ„ κ°€μ§„λ‹€.

    ν…ŒμŠ€νŠΈλ‚˜ 문제 해결이 λ¬΄μ§€ν•˜κ²Œ μ–΄λ ΅λ‹€. 개발 곡정 전체에 λ§Žμ€ 영ν–₯을 끼칠 수 μžˆλ‹€.

    μŠ€λ ˆλ“œ λ“± λ³‘λ ¬μ²˜λ¦¬(비동기)λŠ” κ³ λ„μ˜ μŠ€ν‚¬μ΄ ν•„μš”ν•˜λ‹€.

    Concurrency Utilities의 이용

    πŸ’‘
    μŠ€λ ˆλ“œμ— λŒ€ν•œ κ³ μˆ˜μ€€ API

    Executor Threadλ₯Ό 직접 μ‚¬μš©ν•˜μ§€ μ•Šκ³  병렬 μ²˜λ¦¬κ°€ κ°€λŠ₯ 처리 νš¨μœ¨μ„ 높일 수 μžˆλŠ” μŠ€λ ˆλ“œν’€(thread pool) 등을 이용 κ°€λŠ₯

    μŠ€λ ˆλ“œ μ„Έμ΄ν”„ν•œ μ»¬λ ‰μ…˜ ConcurrentHashMap λ“± κΈ°μ‘΄κ³Ό λ™μΌν•œ κΈ°λŠ₯ + μŠ€λ ˆλ“œ μ„Έμ΄ν”„ν•œ 클래슀λ₯Ό 제곡

    Synchronized λ˜λŠ” Lock 에 κ΄€ν•œ μˆ˜ν–‰ 볡수 μŠ€λ ˆλ“œλ₯Ό 잘 μ‚¬μš©ν•˜κΈ° μœ„ν•œ κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ” ν΄λž˜μŠ€λ“€ λ‹€μˆ˜ 제곡 CountDownLatch, CyclicBarrier, Exchanger, Semaphore λ“±


    πŸ“μ—°μŠ΅ 문제

    11-1

    package com.pkd.exam;
    
    public class CountUpThread {
    
        public CountUpThread() {
            for (int i = 0; i <= 50; i++) {
                System.out.print(i + " ");
            }
            System.out.println();
        }
    }
    package com.pkd.exam;
    
    public class Main {
    
        public static void main(String[] args) {
            for(int i = 0; i < 3; i++) {
                new Thread(() -> {
                    CountUpThread cut = new CountUpThread();
                }).start();
            }
        }
    }
    πŸ’‘
    3개의 μŠ€λ ˆλ“œμ—μ„œ CountUpThreadλ₯Ό μƒμ„±ν•˜κ³  μ‹€ν–‰ν‚€μ‹  κ²°κ³Ό λ™μ‹œμ„±μœΌλ‘œ μˆœμ°¨μ μ΄μ§€ μ•Šμ€ κ²°κ³Όλ₯Ό λ³Ό 수 μžˆμ—ˆλ‹€.

    11-2

    package com.pkd.exam;
    
    public class Counter {
        private long count = 0;
        
        public synchronized void add(long i) {
            System.out.println("λ”ν•˜κΈ°");
            count += i;
        }
        
        public synchronized void mul(long i) {
            System.out.println("κ³±ν•˜κΈ°");
            count *= i;
        }
    
        public long getCount() {
            return count;
        }
    
        public void setCount(long count) {
            this.count = count;
        }
    
    }
    package com.pkd.exam;
    
    public class Main {
        public static void main(String[] args) throws InterruptedException {
            Counter counter = new Counter();
            for (int i = 0; i < 3; i++) {
                new Thread(() -> {
                    counter.add(1);
                    counter.add(1);
                    counter.mul(2);
                    counter.mul(2);
                }).start();
            }
            Thread.sleep(10);
            System.out.println(counter.getCount());
        }
    }

    πŸ’‘
    synchronized ν‚€μ›Œλ“œλ₯Ό 각 λ©”μ„œλ“œμ— μΆ”κ°€ν•˜μ—¬ λ©€ν‹° μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œλ„ μ•ˆμ „ν•˜λ„λ‘ μ„€μ •ν–ˆλ‹€. 정상적인 계산 κ²°κ³Όκ°€ 좜λ ₯된 것을 λ³Ό 수 μžˆμ—ˆλ‹€.

    πŸ’‘
    μŠ€λ ˆλ“œλŠ” μ‚¬λžŒμ΄ 직접 닀루기 μ–΄λ ΅λ‹€. λ”°λΌμ„œ λ˜λ„λ‘ μŠ€λ ˆλ“œλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³ , λ™μ‹œμ„± μ½”λ“œλ‘œ μ„€κ³„ν•˜λŠ” 것이 μ€‘μš”ν•˜λ‹€.
    πŸ’‘
    μŠ€λ ˆλ“œμ˜ 문제 - λ³€μˆ˜μ˜ 값에 μ ‘κ·Όν•΄ 처리 ν•˜λ‹€ λ³΄λ‹ˆ 문제 λ°œμƒ β†’ ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ˜ λ³€μˆ˜κ°€ μ—†λŠ” μƒνƒœ μ œμ–΄λ‘œ λ™μ‹œμ„± ν”„λ‘œκ·Έλž˜λ°


    Uploaded by N2T

    728x90
    λ°˜μ‘ν˜•

    λŒ“κΈ€

Keydi's Tistory