ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 31. 멀티스레드2
    개발자 수업/Java 2021. 10. 25. 18:17
    package kr.co.ezenac.wait2;
    /*
     * 책을 못빌릴 경우에 wait() 호출해서 기다림
     * 책이 반납되어 빌릴 수 있게 될 경우 깨워주는게 notify()임
     */
    import java.util.ArrayList;
    
    class EzenLibrary {
    	
    	public ArrayList<String> books = new ArrayList<>();
    	
    	public EzenLibrary() {
    		books.add("인텔리제이 IEDA1");
    		books.add("인텔리제이 IEDA2");
    		books.add("인텔리제이 IEDA3");
    	}
    	
    	// 책 빌림
    	public synchronized String lendBook() throws InterruptedException {
    		
    		Thread t = Thread.currentThread();
    		
    		if(books.size() == 0) {
    			System.out.println(t.getName() + " waiting start");
    			wait();	//현재 이 스레드를 기다리게 함 (Object의 메서드)
    			System.out.println(t.getName() + " waiting end");
    		}
    		
    		String title = books.remove(0);
    		System.out.println(t.getName() + " : " + title + " lend");	//어떤 스레드가 빌리는지 확인
    		
    		return title;
    	}
    	
    	//책 반납
    	public synchronized void returnBook(String title) {
    		
    		Thread t = Thread.currentThread();
    		System.out.println(t.getName() + " : " + title + " return");	//어떤 스레드가 반납하는지 확인
    		
    		books.add(title);
    		
    		notify();	//wait()하고 있는 스레드를 (하나씩) 깨워줌 (Object의 메서드)
    	}
    }
    
    class Student extends Thread {
    	public Student(String name) {
    		super(name);
    	}
    	
    	@Override
    	public void run() {
    		try {
    			String title = LibraryTest.library.lendBook();
    			
    			if(title == null) {
    				System.out.println(getName() + " : 빌리지 못했음");
    				return;
    			}
    			
    			sleep(5000);	//(5초 동안 책을 읽음)
    			LibraryTest.library.returnBook(title);
    		} catch (InterruptedException e) {
    			System.out.println(e.getMessage());
    			//e.printStackTrace();
    		}
    	}
    }
    
    public class LibraryTest {
    	public static EzenLibrary library = new EzenLibrary();	//shared Resource
    	
    	public static void main(String[] args) {
    		
    		Student stu1 = new Student("학생1");	//리소스는 3개로 한정적인데 사용하려는 스레드는 더 많음
    		Student stu2 = new Student("학생2");
    		Student stu3 = new Student("학생3");
    		Student stu4 = new Student("학생4");
    		Student stu5 = new Student("학생5");
    		Student stu6 = new Student("학생6");
    		
    		stu1.start();
    		stu2.start();
    		stu3.start();
    		stu4.start();
    		stu5.start();
    		stu6.start();
    	}
    }​
    //Tread 클래스 상속하여 만들기
    class MyThread extends Thread {
    	@Override
    	public void run() {
    		int i;
    		for(i=0; i<=50; i++) {
    			System.out.print(i + "\t");
    			
    			try {
    				Thread.sleep(10);
    			} catch (InterruptedException e) {
    				System.out.println(e.getMessage());
    				//e.printStackTrace();
    			}
    		}
    	}
    }
    
    public class ThreadTest {
    	public static void main(String[] args) {
    		System.out.println(Thread.currentThread() + "start");
    		
    		MyThread thread1 = new MyThread();
    		MyThread thread2 = new MyThread();
    		
    		thread1.start();
    		thread2.start();
    		
    		System.out.println(thread1);
    		System.out.println(thread2);
    		
    		System.out.println(Thread.currentThread() + "end");
    	}
    }
    //Runnable 인터페이스 구현하여 만들기
    //자바는 다중 상속이 허용되지 않으므로 이미 다른 클래스를 상속한 경우 thread를 만들기 위해 Runnable interface를 구현하도록 함
    class MyThread2 implements Runnable {
    	@Override
    	public void run() {
    		int i;
    		for(i=0; i<=50; i++) {
    			System.out.print(i + "\t");
    			
    			try {
    				Thread.sleep(10);
    			} catch (InterruptedException e) {
    				System.out.println(e.getMessage());
    				//e.printStackTrace();
    			}
    		}
    	}
    }
    
    public class ThreadTest2 {
    	public static void main(String[] args) {
    		System.out.println(Thread.currentThread() + "start");
    		
    		MyThread2 runner1 = new MyThread2();
    		Thread thread1 = new Thread(runner1);
    		thread1.start();
    		
    		MyThread2 runner2 = new MyThread2();
    		Thread thread2 = new Thread(runner2);
    		thread2.start();
    		
    		System.out.println(thread1);
    		System.out.println(thread2);
    		
    		System.out.println(Thread.currentThread() + "end");
    	}
    }

     


    1. multi-threading
        1) 여러 thread가 동시에 수행되는 프로그래밍. 여러 작업이 동시에 실행되는 효과
        2) thread는 각각 자신만의 작업 공간을 가짐 : context
        3) 각 thread 사이에는 공유하는 자원이 있을 수 있음 (자바에서는 static instance)
        4) 여러 thread가 자원을 공유하여 작업이 수행되는 경우
           서로 자원을 차지하려는 race condition이 발생할 수 있음
        5) 이렇게 여러 thread가 공유하는 자원 중 경쟁이 발생하는 부분을 critical section이라 함
        6) critical section에 대한 동기화(일종의 순차적 수행)를 구현하지 않으면 오류가 발생할 수 있음

    2. Thread Status(스레드 상태)
        (그림 첨부)

    3. Join()
        1) 다른 스레드의 종료를 기다림
        2) 동시에 두 개 이상의 Thread가 실행될 때 다른 Thread의 결과를 참조하여 실행해야 하는 경우 join() 함수를 사용함
        3) join() 함수를 호출한 Thread가 not-runnable 상태가 됨
        4) 다른 Thread의 수행이 끝나면 runnable 상태로 돌아옴

    //1부터 50, 51부터 100까지의 합을 구하는 두 개의 thread 생성
    public class JoinTest extends Thread{
    	
    	int start;
    	int end;
    	int total;
    	
    	public JoinTest(int start, int end) {
    		this.start = start;
    		this.end = end;
    	}
    	
    	@Override
    	public void run() {
    		int i;
    		for(i=start; i<=end; i++) {
    			total += i;
    		}
    	}
    	
    	public static void main(String[] args) {
    		JoinTest joinTest1 = new JoinTest(1, 50);
    		JoinTest joinTest2 = new JoinTest(51, 100);
    		
    		joinTest1.start();
    		joinTest2.start();
    		
    		int lastTotal = joinTest1.total + joinTest2.total;
    		System.out.println("joinTest1.total = " + joinTest1.total);
    		System.out.println("joinTest2.total = " + joinTest2.total);
    		System.out.println("lastTotal = " + lastTotal);
    	}
    }
    //1부터 50, 51부터 100까지의 합을 구하는 두 개의 thread 생성
    public class JoinTest2 extends Thread{
    	
    	int start;
    	int end;
    	int total;
    	
    	public JoinTest2(int start, int end) {
    		this.start = start;
    		this.end = end;
    	}
    	
    	@Override
    	public void run() {
    		int i;
    		for(i=start; i<=end; i++) {
    			total += i;
    		}
    	}
    	
    	public static void main(String[] args) {
    		JoinTest2 joinTest1 = new JoinTest2(1, 50);
    		JoinTest2 joinTest2 = new JoinTest2(51, 100);
    		
    		joinTest1.start();
    		joinTest2.start();
    		
    		try {
    			joinTest1.join();			//스레드 상태 제어
    			joinTest2.join();			//joinTest1, joinTest2에 join()을 main스레드가 호출하고 main스레드는 not running(기다림) 상태임
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		
    		int lastTotal = joinTest1.total + joinTest2.total;
    		System.out.println("joinTest1.total = " + joinTest1.total);
    		System.out.println("joinTest2.total = " + joinTest2.total);
    		System.out.println("lastTotal = " + lastTotal);
    	}
    }



    4. interrupt()
        1) 다른 Thread에 예외를 발생시키는 interrupt을 보냄
        2) Thread가 sleep(시간), wait(), join() 함수에 의해 Not Runnable 상태일 때, interrupt() 메소드를 호출하면 다시 Runnable 상태가 될 수 있음

    public class Sleep extends Thread {
    	@Override
    	public void run() {
    		int i;
    		for(i=0; i<100; i++) {
    			System.out.println(i);
    			
    			try {
    				sleep(50);
    			} catch (InterruptedException e) {
    				System.out.println(e);
    				//e.printStackTrace();
    			}
    		}
    	}
    	
    	public static void main(String[] args) {
    		Sleep sleep = new Sleep();
    		sleep.start();
    		
    		System.out.println("end");
    	}
    }
    public class Sleep2 extends Thread {
    	@Override
    	public void run() {
    		int i;
    		for(i=0; i<100; i++) {
    			System.out.println(i);
    			
    			try {
    				sleep(50);
    			} catch (InterruptedException e) {
    				System.out.println(e);
    				System.out.println("Wake Up");
    				//e.printStackTrace();
    			}
    		}
    	}
    	
    	public static void main(String[] args) {
    		Sleep2 sleep = new Sleep2();
    		sleep.start();
    		
    		sleep.interrupt();
    		
    		System.out.println("end");
    	}
    }



    5. Thread 종료하기
        1) 무한 반복의 경우 while(flag)의 flag 변수 값을 false로 바꾸어 종료를 시킴

    package kr.co.ezenac.terminate;
    
    import java.io.IOException;
    
    public class TerminateThread extends Thread {
    	private boolean flag = false;
    	int i;
    	
    	public boolean isFlag() {
    		return flag;
    	}
    	public void setFlag(boolean flag) {
    		this.flag = flag;
    	}
    	
    	public TerminateThread(String name) {
    		super(name);
    	}
    	
    	@Override
    	public void run() {
    		while(!flag) {
    			try {
    				sleep(100);	//0.1초간 잠들었다가(not running) 깨었다가(running)를 계속 반복
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		System.out.println("end");
    	}
    
    	public static void main(String[] args) throws IOException {
    		TerminateThread threadA = new TerminateThread("A");	//스레드 이름 A
    		TerminateThread threadB = new TerminateThread("B");
    		TerminateThread threadC = new TerminateThread("C");
    		
    		threadA.start();
    		threadB.start();
    		threadC.start();
    		
    		//계속 실행 중인 상태를 멈추게 함
    		int in;
    		while(true) {
    			in = System.in.read();
    			if(in == 'A') {
    				threadA.setFlag(true);	//threadA를 멈추게 함
    			} else if(in == 'B') { 
    				threadB.setFlag(true);	//threadB를 멈추게 함
    			} else if(in == 'C') {
    				threadC.setFlag(true);	//threadC를 멈추게 함
    			} else if(in == 'M') {
    				threadA.setFlag(true);
    				threadB.setFlag(true);
    				threadC.setFlag(true);
    				break;
    			}
    		}
    		System.out.println("main end");
    	}
    }



    6. 멀티 Thread 프로그래밍에서 동기화
        1) critical section : 두 개 이상의 thread가 동시에 접근하는 경우 문제가 생길 수 있기 때문에 동시에 접근할 수 없게 해야 함
        2) 한 순간 오직 하나의 thread만이 공유자원을 얻을 수 있고, 나머지 thread들은 대기(blocking) 상태가 됨

    7. 동기화(synchronization)
        1) 두 개의 thread가 같은 객체에 접근할 경우 동시에 접근함으로써 오류가 발생
        2) 동기화는 임계영역에 접근한 경우 공유자원을 lock하여 다른 thread의 접근을 제어
        3) 동기화를 잘못 구현하면 deadlock에 빠질 수 있음

    8. 자바에서 synchronized 메소드나 synchronized 블럭을 사용
        1) synchronized 블럭
            - 현재 객체 또는 다른 객체를 lock으로 만듦
                synchronized(참조형 수식){
                    수행문;
                }
        2) synchronized 메소드 
            - 객체의 메소드에 synchronized 키워드 사용
            - 현재 이 메소드가 속해있는 객체에 lock을 걺

    package kr.co.ezenac.sync;
    
    class Bank {	//critical section : 두 개 이상의 스레드가 동시에 접근할 수 없는 영역
    	private int money = 10000;
    
    	public int getMoney() {
    		return money;
    	}
    
    	public void setMoney(int money) {
    		this.money = money;
    	}
    	
    	public void saveMoney(int save) {
    		int m = this.getMoney();
    		
    		try {
    			Thread.sleep(3000);	//저축하는데 3초가 걸림(쉼)
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		
    		setMoney(m + save);
    		
    	}
    	
    	public void minusMoney(int minus) {
    		int m = this.getMoney();
    		
    		try {
    			Thread.sleep(200);	//소비하는데 0.2초가 걸림
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		
    		setMoney(m - minus);
    	}
    	
    }
    
    class Ryu extends Thread {
    	@Override
    	public void run() {
    		System.out.println("start save");
    		SyncTest.myBank.saveMoney(3000);	//critical section => 각 스레드에 share됨
    		System.out.println("After save money : " + SyncTest.myBank.getMoney());
    	}
    }
    
    class RyuWife extends Thread {
    	@Override
    	public void run() {
    		System.out.println("start minus");
    		SyncTest.myBank.minusMoney(1000);
    		System.out.println("After minus money : " + SyncTest.myBank.getMoney());
    	}
    }
    
    public class SyncTest {
    	
    	public static Bank myBank = new Bank();
    	
    	public static void main(String[] args) throws InterruptedException {
    		
    		Ryu ryu = new Ryu();
    		ryu.start();
    		
    		Thread.sleep(200);		//0.2초 멈춘 후에
    		
    		RyuWife ryuWife = new RyuWife();
    		ryuWife.start();
    		
    	}
    }
    package kr.co.ezenac.sync2;
    // 두 개의 스레드가 이 은행을 동시에 접근하는 경우 동기화 처리
    class Bank {	//critical section : 두 개 이상의 스레드가 동시에 접근할 수 없는 영역
    	private int money = 10000;
    
    	public int getMoney() {
    		return money;
    	}
    
    	public void setMoney(int money) {
    		this.money = money;
    	}
    	
    	public synchronized void saveMoney(int save) {	//Bank에 lock이 걸림
    		int m = this.getMoney();
    		
    		try {
    			Thread.sleep(3000);	//저축하는데 3초가 걸림(쉼)
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		
    		setMoney(m + save);
    		
    	}
    	
    	public synchronized void minusMoney(int minus) {
    		int m = this.getMoney();
    		
    		try {
    			Thread.sleep(200);	//소비하는데 0.2초가 걸림
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		
    		setMoney(m - minus);
    	}
    	
    }
    
    class Ryu extends Thread {
    	@Override
    	public void run() {
    		System.out.println("start save");
    		SyncTest.myBank.saveMoney(3000);	//critical section => 각 스레드에 share됨
    		System.out.println("After save money : " + SyncTest.myBank.getMoney());
    	}
    }
    
    class RyuWife extends Thread {
    	@Override
    	public void run() {
    		System.out.println("start minus");
    		SyncTest.myBank.minusMoney(1000);
    		System.out.println("After minus money : " + SyncTest.myBank.getMoney());
    	}
    }
    
    public class SyncTest {
    	
    	public static Bank myBank = new Bank();
    	
    	public static void main(String[] args) throws InterruptedException {
    		
    		Ryu ryu = new Ryu();
    		ryu.start();
    		
    		Thread.sleep(200);		//0.2초 멈춘 후에
    		
    		RyuWife ryuWife = new RyuWife();
    		ryuWife.start();
    		
    	}
    }
    package kr.co.ezenac.sync3;
    // 두 개의 스레드가 이 은행을 동시에 접근하는 경우 동기화 처리
    class Bank {	//critical section : 두 개 이상의 스레드가 동시에 접근할 수 없는 영역
    	private int money = 10000;
    
    	public int getMoney() {
    		return money;
    	}
    
    	public void setMoney(int money) {
    		this.money = money;
    	}
    	
    	public void saveMoney(int save) {	//Bank에 lock이 걸림
    		synchronized (this) {
    			int m = this.getMoney();
    			
    			try {
    				Thread.sleep(3000);	//저축하는데 3초가 걸림(쉼)
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			
    			setMoney(m + save);
    		}
    	}
    	
    	public synchronized void minusMoney(int minus) {
    		int m = this.getMoney();
    		
    		try {
    			Thread.sleep(200);	//소비하는데 0.2초가 걸림
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		
    		setMoney(m - minus);
    	}
    	
    }
    
    class Ryu extends Thread {
    	@Override
    	public void run() {
    		System.out.println("start save");
    		SyncTest.myBank.saveMoney(3000);	//critical section => 각 스레드에 share됨
    		System.out.println("After save money : " + SyncTest.myBank.getMoney());
    	}
    }
    
    class RyuWife extends Thread {
    	@Override
    	public void run() {
    		System.out.println("start minus");
    		SyncTest.myBank.minusMoney(1000);
    		System.out.println("After minus money : " + SyncTest.myBank.getMoney());
    	}
    }
    
    public class SyncTest {
    	
    	public static Bank myBank = new Bank();
    	
    	public static void main(String[] args) throws InterruptedException {
    		
    		Ryu ryu = new Ryu();
    		ryu.start();
    		
    		Thread.sleep(200);		//0.2초 멈춘 후에
    		
    		RyuWife ryuWife = new RyuWife();
    		ryuWife.start();
    		
    	}
    }



    9. wait() / notify(), notifyAll() 메소드를 활용한 동기화 프로그래밍
        1) 리소스가 어떤 조건에서 더 이상 유효하지 않은 경우 리소스를 기다리기 위해 Thread가 wait() 상태가 됨 (Not Runnable)
        2) wait() 상태가 된 Thread는 notify()가 호출될 때까지 기다림
        3) 유효한 자원이 생기면 notify() 호출되고 wait()하고 있는 Thread 중 무작위로 하나의 Thread를 재시작 하도록 함 (Runnable)
        4) notifyAll()이 호출되는 경우 wait()하고 있는 모든 Thread가 재시작 됨
            - 이 경우 유효한 리소스만큼의 Thread만이 수행될 수 있고 자원을 갖지 못한 Thread의 경우는 다시 wait() 상태로 만듦
            - notifyAll() 메소드의 사용을 권장

    package kr.co.ezenac.wait;
    
    import java.util.ArrayList;
    
    class EzenLibrary {
    	
    	public ArrayList<String> books = new ArrayList<>();
    	
    	public EzenLibrary() {
    		books.add("인텔리제이 IEDA1");
    		books.add("인텔리제이 IEDA2");
    		books.add("인텔리제이 IEDA3");
    		books.add("인텔리제이 IEDA4");
    		books.add("인텔리제이 IEDA5");
    		books.add("인텔리제이 IEDA6");
    	}
    	
    	// 책 빌림
    	public String lendBook() {
    		String title = books.remove(0);
    		Thread t = Thread.currentThread();
    		System.out.println(t.getName() + " : " + title + "lend");	//어떤 스레드가 빌리는지 확인
    		
    		return title;
    	}
    	
    	//책 반납
    	public void returnBook(String title) {
    		books.add(title);
    		Thread t = Thread.currentThread();
    		System.out.println(t.getName() + " : " + title + "return");	//어떤 스레드가 반납하는지 확인
    	}
    }
    
    class Student extends Thread {
    	public Student(String name) {
    		super(name);
    	}
    	
    	@Override
    	public void run() {
    		try {
    			String title = LibraryTest.library.lendBook();
    			sleep(5000);	//(5초 동안 책을 읽음)
    			LibraryTest.library.returnBook(title);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    }
    
    public class LibraryTest {
    	public static EzenLibrary library = new EzenLibrary();	//shared Resource
    	
    	public static void main(String[] args) {
    		
    		Student stu1 = new Student("학생1");
    		Student stu2 = new Student("학생2");
    		Student stu3 = new Student("학생3");
    		Student stu4 = new Student("학생4");
    		Student stu5 = new Student("학생5");
    		
    		stu1.start();
    		stu2.start();
    		stu3.start();
    		stu4.start();
    		stu5.start();
    	}
    }
    package kr.co.ezenac.wait2;
    /*
     * 책을 못빌릴 경우에 wait() 호출해서 기다림
     * 책이 반납되어 빌릴 수 있게 될 경우 깨워주는게 notify()임
     */
    import java.util.ArrayList;
    
    class EzenLibrary {
    	
    	public ArrayList<String> books = new ArrayList<>();
    	
    	public EzenLibrary() {
    		books.add("인텔리제이 IEDA1");
    		books.add("인텔리제이 IEDA2");
    		books.add("인텔리제이 IEDA3");
    	}
    	
    	// 책 빌림
    	public synchronized String lendBook() throws InterruptedException {
    		
    		Thread t = Thread.currentThread();
    		
    		if(books.size() == 0) {
    			System.out.println(t.getName() + " waiting start");
    			wait();	//현재 이 스레드를 기다리게 함 (Object의 메서드)
    			System.out.println(t.getName() + " waiting end");
    		}
    		
    		String title = books.remove(0);
    		System.out.println(t.getName() + " : " + title + " lend");	//어떤 스레드가 빌리는지 확인
    		
    		return title;
    	}
    	
    	//책 반납
    	public synchronized void returnBook(String title) {
    		
    		Thread t = Thread.currentThread();
    		System.out.println(t.getName() + " : " + title + " return");	//어떤 스레드가 반납하는지 확인
    		
    		books.add(title);
    		
    		notify();	//wait()하고 있는 스레드를 (하나씩) 깨워줌 (Object의 메서드)
    	}
    }
    
    class Student extends Thread {
    	public Student(String name) {
    		super(name);
    	}
    	
    	@Override
    	public void run() {
    		try {
    			String title = LibraryTest.library.lendBook();
    			
    			if(title == null) {
    				System.out.println(getName() + " : 빌리지 못했음");
    				return;
    			}
    			
    			sleep(5000);	//(5초 동안 책을 읽음)
    			LibraryTest.library.returnBook(title);
    		} catch (InterruptedException e) {
    			System.out.println(e.getMessage());
    			//e.printStackTrace();
    		}
    	}
    }
    
    public class LibraryTest {
    	public static EzenLibrary library = new EzenLibrary();	//shared Resource
    	
    	public static void main(String[] args) {
    		
    		Student stu1 = new Student("학생1");	//리소스는 3개로 한정적인데 사용하려는 스레드는 더 많음
    		Student stu2 = new Student("학생2");
    		Student stu3 = new Student("학생3");
    		Student stu4 = new Student("학생4");
    		Student stu5 = new Student("학생5");
    		Student stu6 = new Student("학생6");
    		
    		stu1.start();
    		stu2.start();
    		stu3.start();
    		stu4.start();
    		stu5.start();
    		stu6.start();
    	}
    }
    package kr.co.ezenac.wait3;
    /*
     * 책을 못빌릴 경우에 wait() 호출해서 기다림
     * 책이 반납되어 빌릴 수 있게 될 경우 깨워주는게 notify()임
     * 
     * notify() => 스레드가 한 개만 깨어나므로 경우에 따라서는 못 깨어나는 경우도 있을 수 있음
     * notifyAll() => 모두 다 깨어나게 됨 => 하나만 반납했는데 모두가 빌리는 상황이 되면 문제가 됨
     */
    import java.util.ArrayList;
    
    class EzenLibrary {
    	
    	public ArrayList<String> books = new ArrayList<>();
    	
    	public EzenLibrary() {
    		books.add("인텔리제이 IEDA1");
    		books.add("인텔리제이 IEDA2");
    		books.add("인텔리제이 IEDA3");
    	}
    	
    	// 책 빌림
    	public synchronized String lendBook() throws InterruptedException {
    		
    		Thread t = Thread.currentThread();
    		
    		while(books.size() == 0) {
    			System.out.println(t.getName() + " waiting start");
    			wait();	//현재 이 스레드를 기다리게 함 (Object의 메서드)
    			System.out.println(t.getName() + " waiting end");
    		}
    		
    		if(books.size() > 0) {
    			String title = books.remove(0);
    			System.out.println(t.getName() + " : " + title + " lend");	//어떤 스레드가 빌리는지 확인
    			return title;
    		} else {
    			return null;
    		}
    	}
    	
    	//책 반납
    	public synchronized void returnBook(String title) {
    		
    		Thread t = Thread.currentThread();
    		System.out.println(t.getName() + " : " + title + " return");	//어떤 스레드가 반납하는지 확인
    		
    		books.add(title);
    		
    		notifyAll();	//wait()하고 있는 스레드를 다 깨워줌 (Object의 메서드)
    	}
    }
    
    class Student extends Thread {
    	public Student(String name) {
    		super(name);
    	}
    	
    	@Override
    	public void run() {
    		try {
    			String title = LibraryTest.library.lendBook();
    			
    			if(title == null) {
    				System.out.println(getName() + " : 빌리지 못했음");
    				return;
    			}
    			
    			sleep(5000);	//(5초 동안 책을 읽음)
    			LibraryTest.library.returnBook(title);
    		} catch (InterruptedException e) {
    			System.out.println(e.getMessage());
    			//e.printStackTrace();
    		}
    	}
    }
    
    public class LibraryTest {
    	public static EzenLibrary library = new EzenLibrary();	//shared Resource
    	
    	public static void main(String[] args) {
    		
    		Student stu1 = new Student("학생1");	//리소스는 3개로 한정적인데 사용하려는 스레드는 더 많음
    		Student stu2 = new Student("학생2");
    		Student stu3 = new Student("학생3");
    		Student stu4 = new Student("학생4");
    		Student stu5 = new Student("학생5");
    		Student stu6 = new Student("학생6");
    		
    		stu1.start();
    		stu2.start();
    		stu3.start();
    		stu4.start();
    		stu5.start();
    		stu6.start();
    	}
    }

    '개발자 수업 > Java' 카테고리의 다른 글

    문제 2 - Chap09 / kr.co.ezenac.assignment  (0) 2021.10.26
    문제 1 - Chap13 / kr.co.ezenac.review02  (0) 2021.10.26
    30. Review  (0) 2021.10.25
    29. 멀티스레드  (0) 2021.10.22
    28. IO입출력  (0) 2021.10.20

    댓글