ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] μžλ°” μ“°λ ˆλ“œμ˜ 동기화
    Android 2021. 2. 7. 16:57
    λ°˜μ‘ν˜•
    • 이 글은 "μžλ°” 온라인 μŠ€ν„°λ””" κ³΅λΆ€ν•˜μ—¬ μž‘μ„±ν•œ κΈ€μž…λ‹ˆλ‹€.

    μ“°λ ˆλ“œ λ™κΈ°ν™”λž€?

    λ©€ν‹° μ“°λ ˆλ“œ ν”„λ‘œκ·Έλž˜λ°μ—μ„œ 동기화 μž‘μ—…μ΄ ν•„μˆ˜μž…λ‹ˆλ‹€. μ“°λ ˆλ“œ λ™κΈ°ν™”λž€ μ—¬λŸ¬ μ“°λ ˆλ“œκ°€ λ™μΌν•œ λ¦¬μ†ŒμŠ€λ₯Ό κ³΅μœ ν•˜μ—¬ μ‚¬μš©ν•˜κ²Œ 되면 μ„œλ‘œμ˜ 결과에 영ν–₯을 μ£ΌκΈ° λ•Œλ¬Έμ— λ°©μ§€ν•˜λŠ” κΈ°λ²•μž…λ‹ˆλ‹€.
    μ“°λ ˆλ“œ 동기화λ₯Ό ν•˜κΈ° μœ„ν•΄μ„œλŠ” μž„κ³„μ˜μ—­(critical section)κ³Ό 락(lock)을 μ‚¬μš©ν•©λ‹ˆλ‹€. μž„κ³„μ˜μ—­μœΌλ‘œ μ„€μ •ν•œ ꡬ역은 λ™μ‹œμ— λ¦¬μ†ŒμŠ€λ₯Ό μ‚¬μš©ν•  수 μ—†λŠ” ꡬ역이고, 락을 νšλ“ν•œ μ“°λ ˆλ“œμ— λŒ€ν•΄μ„œλ§Œ λ¦¬μ†ŒμŠ€λ₯Ό μ‚¬μš©ν•˜λ„λ‘ ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€.



    synchronizedλ₯Ό μ΄μš©ν•œ 동기화

    μžλ°”μ—μ„œλŠ” synchronized ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ μž„κ³„μ˜μ—­μ„ μ§€μ •ν•˜μ—¬ λ™μ‹œμ— κ³΅μœ μžμ›μ„ μ°¨μ§€ν•˜μ§€ μ•Šλ„λ‘ κ°•μ œν•©λ‹ˆλ‹€. synchronizedλ₯Ό μ‚¬μš©ν•˜λŠ” 방법을 λ©”μ†Œλ“œ μžμ²΄μ— μ μš©ν•˜κ±°λ‚˜, μ½”λ“œ 블둝에 μ μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    • λ©”μ†Œλ“œ 전체λ₯Ό μž„κ³„μ˜μ—­μ„ 지정 : λ©”μ†Œλ“œ μ„ μ–Έ μ‹œμ— synchronized ν‚€μ›Œλ“œ μΆ”κ°€, 이 λ©”μ†Œλ“œκ°€ 호좜되면 λ©”μ†Œλ“œλ₯Ό 가지고 μžˆλŠ” 객체에 λŒ€ν•œ 락을 νšλ“ν•˜μ—¬ μž‘μ—…μ„ μˆ˜ν–‰ν•˜λ‹€κ°€ λ©”μ†Œλ“œ μ’…λ£Œλ˜λ©΄ 락을 λ°˜λ‚©ν•©λ‹ˆλ‹€.

    • νŠΉμ • μ˜μ—­λ§Œ μž„κ³„μ˜μ—­μ„ 지정 : synchronized ν‚€μ›Œλ“œλ‘œ μ‹œμž‘ν•˜λŠ” λΈ”λ‘μœΌλ‘œ 지정, νŠΉμ • 객체λ₯Ό μ§€μ •ν•˜μ—¬ 블둝 λ‚΄μ—μ„œ 객체에 λŒ€ν•œ 락을 νšλ“ν•˜κ³  블둝을 λ²—μ–΄λ‚˜λ©΄ 락을 λ°˜λ‚©ν•©λ‹ˆλ‹€.

     

    synchronized μ‹€μŠ΅ μ½”λ“œ

    public class Student {
    
        int bookCount = 5;      // 곡유 μžμ›
    
        public int getBookCount() {
            return bookCount;
        }
    
        public void setBookCount(int bookCount) {
            this.bookCount = bookCount;
        }
    
        public void borrowBook() throws InterruptedException {
            int m = bookCount;
            Thread.sleep(2000);
            bookCount = m+1;
            System.out.println("λŒ€μΆœμ™„λ£Œ");
        }
    
        public void returnBook() throws InterruptedException {
            int m = bookCount;
            Thread.sleep(3000);
            bookCount = m-1;
            System.out.println("λ°˜λ‚©μ™„λ£Œ");
        }
    }
    public class Library {
        public  static Student student = new Student();
    }
    public class BorrowThread extends Thread{
        @Override
        public void run() {
            try {
                Library.student.borrowBook();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("학생이 빌린 총 μ±…μ˜ 갯수 : "+Library.student.getBookCount());
        }
    }
    public class ReturnThread extends Thread{
        @Override
        public void run() {
            try {
                Library.student.returnBook();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("학생이 빌린 총 μ±…μ˜ 갯수 : "+Library.student.getBookCount());
        }
    }
    public class Main {
        public static void main(String[] args) {
            System.out.println("ν˜„μž¬ λŒ€μΆœν•œ μ±…μ˜ 갯수 : "+Library.student.getBookCount());
    
            BorrowThread bt = new BorrowThread();
            ReturnThread rt = new ReturnThread();
    
            bt.setPriority(10);
            bt.start();
            rt.start();
    
            try{
                bt.join();
                rt.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    λ‹€μŒ μ˜ˆμ œλŠ” 동기화λ₯Ό ν•˜μ§€ μ•Šμ•„μ„œ λ¬Έμ œκ°€ λ˜λŠ” μ½”λ“œμž…λ‹ˆλ‹€. μ½”λ“œλ₯Ό 보고 μ–΄λŠ μ§€μ μ—μ„œ λ¬Έμ œκ°€ 생길지 μ•ˆλ‹€λ©΄ 동기화에 λŒ€ν•΄ 이미 μ–΄λŠμ •λ„ μ•Œκ³  κ³„μ‹ κ²λ‹ˆλ‹€.

    μ‹€ν–‰ κ²°κ³Όλ₯Ό 보면 학생이 ν˜„μž¬ λŒ€μΆœν•œ 책은 총 5κΆŒμ΄μ—ˆμŠ΅λ‹ˆλ‹€. 그리고 ν•œ κΆŒμ„ λŒ€μΆœν•œ ν›„ λ°˜λ‚©μ„ ν•˜μ—¬ ν˜„μž¬ 학생이 빌린 μ±…μ˜ κ°―μˆ˜λŠ” 처음과 동일해야 ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ λŒ€μΆœν•˜κ³  λ‚œ ν›„ 책은 6ꢌ이 λ˜μ—ˆμ§€λ§Œ, λ°˜λ‚©μ„ ν•˜λ‹ˆ 5ꢌ이 μ•„λ‹Œ 4ꢌ이 λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

        public void borrowBook() throws InterruptedException {
            int m = bookCount;
            Thread.sleep(2000);
            bookCount = m+1;
            System.out.println("λŒ€μΆœμ™„λ£Œ");
        }
    
        public void returnBook() throws InterruptedException {
            int m = bookCount;
            Thread.sleep(3000);
            bookCount = m-1;
            System.out.println("λ°˜λ‚©μ™„λ£Œ");
        }

    원인을 뢄석해 보자면, BorrowThreadλŠ” borrowBook λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜κ³  ReturnThreadλŠ” returnBook λ©”μ†Œλ“œλ₯Ό λ™μ‹œμ— ν˜ΈμΆœν•©λ‹ˆλ‹€. 그에 따라, μ§€μ—­λ³€μˆ˜ mμ—λŠ” ν˜„μž¬ bookCount인 5κ°€ λͺ¨λ‘ λŒ€μž…μ΄ 되고, λͺ‡ μ΄ˆκ°„μ˜ λ”œλ ˆμ΄ ν›„ bookCount에 값을 λŒ€μž…ν•˜κΈ° λ•Œλ¬Έμ— +1일 λ•ŒλŠ” 6이되고 -1일 λ•ŒλŠ” 4κ°€ λ˜λŠ” κ²ƒμž…λ‹ˆλ‹€.
    이λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄μ„œλŠ” synchronized ν‚€μ›Œλ“œλ‘œ μž„κ³„μ˜μ—­μ„ μ§€μ •ν•˜μ—¬ 동기화λ₯Ό ν•΄μ•Ό ν•©λ‹ˆλ‹€.

        public synchronized void borrowBook() throws InterruptedException {
            int m = bookCount;
            Thread.sleep(2000);
            bookCount = m+1;
            System.out.println("λŒ€μΆœμ™„λ£Œ");
        }
    
        public synchronized void returnBook() throws InterruptedException {
            int m = bookCount;
            Thread.sleep(3000);
            bookCount = m-1;
            System.out.println("λ°˜λ‚©μ™„λ£Œ");
        }

    Student의 λ©”μ†Œλ“œμΈ boroowBookκ³Ό returnBook에 synchronized ν‚€μ›Œλ“œλ₯Ό μΆ”κ°€ν•˜μ˜€μŠ΅λ‹ˆλ‹€. 이 λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•  κ²½μš°μ—λŠ” Student객체에 λŒ€ν•œ 락을 μ–»κ³  락을 얻지 λͺ»ν•œ κ°μ²΄λŠ” 락을 λ°˜λ‚©ν•  λ•ŒκΉŒμ§€ κΈ°λ‹€λ €μ•Ό ν•©λ‹ˆλ‹€.
    λ”°λΌμ„œ, borrowThreadκ°€ λ¨Όμ € Student 객체 락을 νšλ“ν•˜κ³  borrowBook λ©”μ†Œλ“œλ₯Ό μ‹€ν–‰ν•©λ‹ˆλ‹€. λ©”μ†Œλ“œκ°€ μ’…λ£Œλ˜μ–΄ 락이 λ°˜λ‚©λœ 이후 ReturnThread의 returnBook λ©”μ†Œλ“œκ°€ ν˜ΈμΆœλ©λ‹ˆλ‹€.

    μ‹€ν–‰ κ²°κ³Ό μ›ν•˜λŠ” κ²°κ³Όλ₯Ό 얻을 수 μžˆμŠ΅λ‹ˆλ‹€.

        public void borrowBook() throws InterruptedException {
            synchronized (this){
                int m = bookCount;
                Thread.sleep(2000);
                bookCount = m+1;
                System.out.println("λŒ€μΆœμ™„λ£Œ");
            }
        }
    
        public void returnBook() throws InterruptedException {
            synchronized (this){
                int m = bookCount;
                Thread.sleep(3000);
                bookCount = m-1;
                System.out.println("λ°˜λ‚©μ™„λ£Œ");
            }
        }

    λ©€ν‹° μ“°λ ˆλ“œ ν”„λ‘œκ·Έλž˜λ°μ—μ„œ μž„κ³„ μ˜μ—­μ€ μ„±λŠ₯을 μ’Œμš°ν•˜κΈ° λ•Œλ¬Έμ— κ°€λŠ₯ν•˜λ©΄ λ©”μ†Œλ“œ 전체 락을 κ±°λŠ” κ²ƒλ³΄λ‹€λŠ” synchronized λΈ”λŸ­μœΌλ‘œ μž„κ³„μ˜μ—­μ„ μ΅œμ†Œν™”ν•΄μ„œ 효율적인 ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

     

    wait(), notify() 동기화

    public class Student {
    
        int bookCount = 0;      // 곡유 μžμ›
    
        public int getBookCount() {
            return bookCount;
        }
    
        public void setBookCount(int bookCount) {
            this.bookCount = bookCount;
        }
    
        public synchronized void borrowBook() throws InterruptedException {
            if(bookCount>=10){
                try{
                    System.out.println("10ꢌ 초과둜 λŒ€μΆœν•  수 μ—†μŠ΅λ‹ˆλ‹€");
                }catch (Exception e){
    
                }
            }
            int m = bookCount;
            bookCount = m+1;
            System.out.println("μ±… λŒ€μΆœ 성곡. λŒ€μΆœν•œ μ±…μ˜ 갯수 : "+bookCount);
        }
    
        public synchronized void returnBook() throws InterruptedException {
            if(bookCount<=0){
                try{
                    System.out.println("λ°˜λ‚©ν•  책이 μ—†μŠ΅λ‹ˆλ‹€");
                }catch (Exception e){
    
                }
            }
            int m = bookCount;
            bookCount = m-1;
            System.out.println("μ±… λ°˜λ‚© 성곡. λŒ€μΆœν•œ μ±…μ˜ 갯수 : "+bookCount);
        }
    }
    public class Library {
        public  static Student student = new Student();
    }
    public class BorrowThread extends Thread{
        @Override
        public void run() {
            for(int i=0;i<30;i++){
                try {
                    Library.student.borrowBook();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public class ReturnThread extends Thread{
        @Override
        public void run() {
    
            for(int i=0;i<30;i++){
                try {
                    Library.student.returnBook();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public class Main {
        public static void main(String[] args) {
            System.out.println("ν˜„μž¬ λŒ€μΆœν•œ μ±…μ˜ 갯수 : "+Library.student.getBookCount());
    
            BorrowThread bt = new BorrowThread();
            ReturnThread rt = new ReturnThread();
    
            bt.setPriority(10);
            bt.start();
            rt.start();
    
            try{
                bt.join();
                rt.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    λ‹€μŒ μ½”λ“œλŠ” synchronized ν‚€μ›Œλ“œλ‘œ 동기화가 λ˜μ–΄ 있기 λ•Œλ¬Έμ— λŒ€μΆœν•œ μ±…μ˜ μˆ˜κ°€ 10ꢌ이 λ„˜λ”λΌλ„ BorrowThreadκ°€ μ’…λ£Œλœ 후에 ReturnThreadκ°€ μ‹€ν–‰λ˜λŠ” 것을 확인할 수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.
    μ œκ°€ μ›ν•˜λŠ” κ²°κ³ΌλŠ” μ΅œλŒ€ 빌릴 수 μžˆλŠ” μˆ˜λŠ” 10ꢌ이고 10κΆŒμ„ 이미 λΉŒλ Έμ„ 경우 λ°˜λ‚©λΆ€ν„° μ§„ν–‰ν•˜λ„λ‘ ν•˜κ³  μ‹Άμ—ˆμŠ΅λ‹ˆλ‹€. κ·Έλ ‡κ²Œ ν•˜κΈ° μœ„ν•΄μ„œλŠ” 빌린 μ±…μ˜ μˆ˜κ°€ 10ꢌ이 되면 락을 λ°˜λ‚©ν•˜μ—¬ ReturnThreadκ°€ μ‹€ν–‰λ˜λ„λ‘ ν•˜λŠ” λ°©λ²•μž…λ‹ˆλ‹€. λ˜ν•œ, λ°˜λ‚©ν•  μ±…μ˜ μˆ˜κ°€ μ—†λ‹€λ©΄ λŒ€μΆœμ΄ κ°€λŠ₯ν•˜λ„λ‘ BorrowThreadμ—κ²Œ 락을 μ£ΌλŠ” λ°©λ²•μž…λ‹ˆλ‹€.

        public synchronized void borrowBook() throws InterruptedException {
            if(bookCount>=10){
                try{
                    System.out.println("10ꢌ 초과둜 λŒ€μΆœν•  수 μ—†μŠ΅λ‹ˆλ‹€");
                    wait();
                }catch (Exception e){
    
                }
            }
            int m = bookCount;
            bookCount = m+1;
            System.out.println("μ±… λŒ€μΆœ 성곡. λŒ€μΆœν•œ μ±…μ˜ 갯수 : "+bookCount);
            notify();
        }
    
        public synchronized void returnBook() throws InterruptedException {
            if(bookCount<=0){
                try{
                    System.out.println("λ°˜λ‚©ν•  책이 μ—†μŠ΅λ‹ˆλ‹€");
                    wait();
                }catch (Exception e){
    
                }
            }
            int m = bookCount;
            bookCount = m-1;
            System.out.println("μ±… λ°˜λ‚© 성곡. λŒ€μΆœν•œ μ±…μ˜ 갯수 : "+bookCount);
            notify();
        }

    λ‹€μŒκ³Ό 같이 μ½”λ“œλ₯Ό μˆ˜μ •ν•˜κ²Œ 되면 10ꢌ 초과둜 λŒ€μΆœν•  수 μ—†κ³  0ꢌ이 되면 λ°˜λ‚©ν•  수 없도둝 ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

    λ°˜μ‘ν˜•
Designed by Tistory.