관리 메뉴

거니의 velog

230901_스레드 4 본문

대덕인재개발원_자바기반 애플리케이션

230901_스레드 4

Unlimited00 2023. 9. 1. 14:35

[HorseGame.java]

package kr.or.ddit.basic;

import java.util.Arrays;

/*
10마리의 말들이 경주하는 프로그램을 작성하시오.

말은 Horse라는 이름의 쓰레드 클래스로 작성하는데 이 클래스는 말이름(String), 등수(int), 현재위치(int)를 
멤버변수로 갖는다. 그리고 이 클래스에는 등수를 오름차순으로 정렬할 수 있는 내부 정렬 기준이 있다. 
(Comparable 인터페이스 구현)

조건)

1) 경기 구간은 1 ~ 50구간으로 되어 있다.
2) 경기가 끝나면 등수 순으로 출력한다.
3) 경기 중에는 중간 중간에 각 말들의 위치를 아래와 같이 나타내 준다.

예시)
01번말 : --->-----------------------------------
02번말 : ------->-------------------------------
...
10번말 : ----->---------------------------------

*/

public class HorseGame {

	public static void main(String[] args) {
		
		Horse2[] horses = new Horse2[] {
			new Horse2("01번말"),
			new Horse2("02번말"),
			new Horse2("03번말"),
			new Horse2("04번말"),
			new Horse2("05번말"),
			new Horse2("06번말"),
			new Horse2("07번말"),
			new Horse2("08번말"),
			new Horse2("09번말"),
			new Horse2("10번말")
		};
		
		GameBoard gb = new GameBoard(horses);
		
		// 경주 시작 ==> 쓰레드 시작
		for(Horse2 h : horses) {
			h.start();
		}
		
		gb.start(); // 말의 현재 위치 출력용 쓰레드 실행
		
		// 모든 말의 경주가 끝날 때까지 기다린다.
		for(Horse2 h : horses) {
			try {
				h.join();
			} catch (InterruptedException e) {
				// TODO: handle exception
			}
		}
		
		try {
			gb.join();
		} catch (InterruptedException e) {
			// TODO: handle exception
		}
		
		System.out.println();
		System.out.println("경기 끝......");
		System.out.println();
		
		// 등수의 오름차순으로 정렬한다.
		Arrays.sort(horses);
		
		System.out.println("=== 경기 결과 ===");
		for(Horse2 h : horses) {
			System.out.println(h);
		}
		
	}

}

//말은 Horse라는 이름의 쓰레드 클래스로 작성하는데 이 클래스는 말이름(String), 등수(int), 현재위치(int)를 
//멤버변수로 갖는다. 그리고 이 클래스에는 등수를 오름차순으로 정렬할 수 있는 내부 정렬 기준이 있다. 
//(Comparable 인터페이스 구현)
class Horse2 extends Thread implements Comparable<Horse2> {
	
	// 등수를 구하기 위한 변수(각 말들<쓰레드들>이 공통으로 사용한다.)
	public static int currentRank = 0; 
	
	private String horseName; // 말이름
	private int rank; // 등수
	private int location; // 현재 위치
	
	// 생성자
	public Horse2(String horseName) {
		this.horseName = horseName;
	}

	public String getHorseName() {
		return horseName;
	}

	public void setHorseName(String horseName) {
		this.horseName = horseName;
	}

	public int getRank() {
		return rank;
	}

	public void setRank(int rank) {
		this.rank = rank;
	}

	public int getLocation() {
		return location;
	}

	public void setLocation(int location) {
		this.location = location;
	}

	@Override
	public String toString() {
		return "경주마 " + horseName + "은(는) " + rank + "등 입니다.";
	}

	// 등수의 오름차순으로 정렬하는 정렬 기준 구성하기
	@Override
	public int compareTo(Horse2 horse) {
		return Integer.compare(this.rank, horse.getRank());
	}
	
	@Override
	public void run() {
		
		// 경기 구간은 1 ~ 50 구간으로 되어 있다.
		for(int i=1; i<=50; i++) {
			this.location = i; // 말의 현재 위치를 저장한다.
			try {
				Thread.sleep((int)(Math.random() * 500 + 1)); // 1 ~ 500 사이의 난수
			} catch (InterruptedException e) {
				// TODO: handle exception
			}
		}
		
		// 현재 말의 경기가 끝난다. ==> 등수를 구해서 저장한다.
		currentRank++;
		this.rank = currentRank;
		
	}
	
}

//예시)
//01번말 : --->-----------------------------------
//02번말 : ------->-------------------------------
//...
//10번말 : ----->---------------------------------
class GameBoard extends Thread {
	
	private Horse2[] horses;
	
	// 생성자
	public GameBoard(Horse2[] horses) {
		this.horses = horses;
	}

	@Override
	public void run() {
		while(true) {
			
			// 모든 말들의 경기가 종료되었는지 여부를 검사한다.
			if(Horse2.currentRank == horses.length) {
				break;
			}
			
			// 각 텀 사이의 빈 줄 출력
			for(int i=1; i<=15; i++) {
				System.out.println();
			}
			
//			System.out.println("**************************************************************************");
			
			for(Horse2 h : horses) {
				// 01번말 : --->-----------------------------------
				System.out.print(h.getHorseName() + " : ");
				
				for(int i=1; i<=50; i++) {
					if(h.getLocation() == i) { // 말의 현재 위치 확인
						System.out.print(">");
					}else {
						System.out.print("-");
					}
				}
				System.out.println(); // 줄바꿈.
			}
			
//			System.out.println("**************************************************************************");
			
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO: handle exception
			}
			
		}
	}
	
}


[ThreadTest13.java]

package kr.or.ddit.basic;

/*
 * Thread의 stop()메서드를 호출하면 쓰레드가 바로 멈춘다.
 * 이 때 사용하던 자원을 정리하지 못하고 쓰레드가 종료되어 
 * 다른 쓰레드의 실행에 영향을 줄 수 있다.
 * 그래서 stop()메서드는 비추천으로 되어 있다.
 */

public class ThreadTest13 {

	public static void main(String[] args) {
		
		ThreadStopTest01 th1 = new ThreadStopTest01();
		
		th1.start();
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO: handle exception
		}
		
//		th1.stop();
		th1.setStop(true);
		
	}

}

// 쓰레드를 멈추게 하는 연습용 쓰레드
class ThreadStopTest01 extends Thread {
	
	private boolean stop;
	
	public void setStop(boolean stop) {
		this.stop = stop;
	}
	
	@Override
	public void run() {
		
		while(!stop) {
			System.out.println(" 쓰레드의 처리내용 실행 중... ");
		}
		
		System.out.println("사용하던 자원을 정리한다...");
		System.out.println("쓰레드 종료...");
		
	}
	
}

package kr.or.ddit.basic;

/*
 * Thread의 stop()메서드를 호출하면 쓰레드가 바로 멈춘다.
 * 이 때 사용하던 자원을 정리하지 못하고 쓰레드가 종료되어 
 * 다른 쓰레드의 실행에 영향을 줄 수 있다.
 * 그래서 stop()메서드는 비추천으로 되어 있다.
 */

public class ThreadTest13 {

	public static void main(String[] args) {
		
		/*
		ThreadStopTest01 th1 = new ThreadStopTest01();
		
		th1.start();
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO: handle exception
		}
		
//		th1.stop();
		th1.setStop(true);
		*/
		
		ThreadStopTest02 th2 = new ThreadStopTest02();
		th2.start();
		
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO: handle exception
		}
		
		th2.interrupt();
		
	}

}

// 쓰레드를 멈추게 하는 연습용 쓰레드
class ThreadStopTest01 extends Thread {
	
	private boolean stop;
	
	public void setStop(boolean stop) {
		this.stop = stop;
	}
	
	@Override
	public void run() {
		
		while(!stop) {
			System.out.println(" 쓰레드의 처리내용 실행 중... ");
		}
		
		System.out.println("사용하던 자원을 정리한다...");
		System.out.println("쓰레드 종료...");
		
	}
	
}

// interrupt() 메서드를 이용하여 쓰레드를 멈추게 하는 연습용 쓰레드
class ThreadStopTest02 extends Thread {
	@Override
	public void run() {
		
		/*
		// 방법1 ==> interrupt()메서드와 sleep()메서드를 이용하는 방법
		try {
			while(true) {
				System.out.println("쓰레드 실행 중...");
				Thread.sleep(1);
			}
		} catch (InterruptedException e) {
			// TODO: handle exception
		}
		*/
		
		// 방법2
		while(true) {
			System.out.println("Thread 실행 중...");
			
			// interrupt()메서드가 호출되었는지 여부를 검사한다.
			
			/*
			// 검사방법1 ==> 쓰레드의 인스턴스 메서드 중 isInterrupted() 메서드를 이용한다.
			// 		isInterrupted() 메서드 ==> interrupt() 메서드가 호출되면 true를 반환한다.
			if(this.isInterrupted()) {
				break;
			}
			*/
			
			// 검사방법2 ==> 쓰레드의 정적(static) 메서드인 interrupted() 메서드를 이용한다.
			// 		interrupted() 메서드 ==> interrupt() 메서드가 호출되면 true를 반환한다.
			if(Thread.interrupted()) {
				break;
			}
		}
		
		System.out.println();
		System.out.println("자원 정리...");
		System.out.println("쓰레드 끝.........");
		
	}
}

[interrupt() 메서드 적용한 코드]

package kr.or.ddit.basic;

import java.util.Arrays;

/*
10마리의 말들이 경주하는 프로그램을 작성하시오.

말은 Horse라는 이름의 쓰레드 클래스로 작성하는데 이 클래스는 말이름(String), 등수(int), 현재위치(int)를 
멤버변수로 갖는다. 그리고 이 클래스에는 등수를 오름차순으로 정렬할 수 있는 내부 정렬 기준이 있다. 
(Comparable 인터페이스 구현)

조건)

1) 경기 구간은 1 ~ 50구간으로 되어 있다.
2) 경기가 끝나면 등수 순으로 출력한다.
3) 경기 중에는 중간 중간에 각 말들의 위치를 아래와 같이 나타내 준다.

예시)
01번말 : --->-----------------------------------
02번말 : ------->-------------------------------
...
10번말 : ----->---------------------------------

*/

public class HorseGame {

	public static void main(String[] args) {
		
		Horse2[] horses = new Horse2[] {
			new Horse2("01번말"),
			new Horse2("02번말"),
			new Horse2("03번말"),
			new Horse2("04번말"),
			new Horse2("05번말"),
			new Horse2("06번말"),
			new Horse2("07번말"),
			new Horse2("08번말"),
			new Horse2("09번말"),
			new Horse2("10번말")
		};
		
		GameBoard gb = new GameBoard(horses);
		
		// 경주 시작 ==> 쓰레드 시작
		for(Horse2 h : horses) {
			h.start();
		}
		
		gb.start(); // 말의 현재 위치 출력용 쓰레드 실행
		
		// 모든 말의 경주가 끝날 때까지 기다린다.
		for(Horse2 h : horses) {
			try {
				h.join();
			} catch (InterruptedException e) {
				// TODO: handle exception
			}
		}
		
		gb.interrupt();
		
		try {
			gb.join();
		} catch (InterruptedException e) {
			// TODO: handle exception
		}
		
		System.out.println();
		System.out.println("경기 끝......");
		System.out.println();
		
		// 등수의 오름차순으로 정렬한다.
		Arrays.sort(horses);
		
		System.out.println("=== 경기 결과 ===");
		for(Horse2 h : horses) {
			System.out.println(h);
		}
		
	}

}

//말은 Horse라는 이름의 쓰레드 클래스로 작성하는데 이 클래스는 말이름(String), 등수(int), 현재위치(int)를 
//멤버변수로 갖는다. 그리고 이 클래스에는 등수를 오름차순으로 정렬할 수 있는 내부 정렬 기준이 있다. 
//(Comparable 인터페이스 구현)
class Horse2 extends Thread implements Comparable<Horse2> {
	
	// 등수를 구하기 위한 변수(각 말들<쓰레드들>이 공통으로 사용한다.)
	public static int currentRank = 0; 
	
	private String horseName; // 말이름
	private int rank; // 등수
	private int location; // 현재 위치
	
	// 생성자
	public Horse2(String horseName) {
		this.horseName = horseName;
	}

	public String getHorseName() {
		return horseName;
	}

	public void setHorseName(String horseName) {
		this.horseName = horseName;
	}

	public int getRank() {
		return rank;
	}

	public void setRank(int rank) {
		this.rank = rank;
	}

	public int getLocation() {
		return location;
	}

	public void setLocation(int location) {
		this.location = location;
	}

	@Override
	public String toString() {
		return "경주마 " + horseName + "은(는) " + rank + "등 입니다.";
	}

	// 등수의 오름차순으로 정렬하는 정렬 기준 구성하기
	@Override
	public int compareTo(Horse2 horse) {
		return Integer.compare(this.rank, horse.getRank());
	}
	
	@Override
	public void run() {
		
		// 경기 구간은 1 ~ 50 구간으로 되어 있다.
		for(int i=1; i<=50; i++) {
			this.location = i; // 말의 현재 위치를 저장한다.
			try {
				Thread.sleep((int)(Math.random() * 500 + 1)); // 1 ~ 500 사이의 난수
			} catch (InterruptedException e) {
				// TODO: handle exception
			}
		}
		
		// 현재 말의 경기가 끝난다. ==> 등수를 구해서 저장한다.
		currentRank++;
		this.rank = currentRank;
		
	}
	
}

//예시)
//01번말 : --->-----------------------------------
//02번말 : ------->-------------------------------
//...
//10번말 : ----->---------------------------------
class GameBoard extends Thread {
	
	private Horse2[] horses;
	
	// 생성자
	public GameBoard(Horse2[] horses) {
		this.horses = horses;
	}

	@Override
	public void run() {
		while(true) {
			
			// 모든 말들의 경기가 종료되었는지 여부를 검사한다.
//			if(Horse2.currentRank == horses.length) {
//				break;
//			}
			
			// interrupt()메서드를 이용한 종료 처리
			if(this.isInterrupted()) {
				break;
			}
			
			// 각 텀 사이의 빈 줄 출력
			for(int i=1; i<=15; i++) {
				System.out.println();
			}
			
//			System.out.println("**************************************************************************");
			
			for(Horse2 h : horses) {
				// 01번말 : --->-----------------------------------
				System.out.print(h.getHorseName() + " : ");
				
				for(int i=1; i<=50; i++) {
					if(h.getLocation() == i) { // 말의 현재 위치 확인
						System.out.print(">");
					}else {
						System.out.print("-");
					}
				}
				System.out.println(); // 줄바꿈.
			}
			
//			System.out.println("**************************************************************************");
			
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				this.interrupt();
			}
			
		}
	}
	
}


[ThreadTest14.java]

package kr.or.ddit.basic;

// 쓰레드에서 객체를 공통으로 사용하는 예제

/*
 * 원주율을 계산하는 쓰레드와 
 * 계산된 원주율을 출력하는 쓰레드가 있다.
 * 
 * 원주율을 관리하는 객체가 필요하다.
 * 이 객체를 두 스레드에서 공통으로 사용해서 처리한다.
 */

public class ThreadTest14 {

	public static void main(String[] args) {
		
		// 공통으로 사용할 객체 생성
		ShareData sd = new ShareData();
		
		// 쓰레드 객체들을 생성하고 공통으로 사용할 객체를 각각의 쓰레드에 주입한다.
		CalcPIThread th1 = new CalcPIThread();
		th1.setSd(sd);
		
		PrintPIThread th2 = new PrintPIThread(sd);
		
		th1.start();
		th2.start();
		
	}

}

// 원주율을 계산하는 쓰레드
class CalcPIThread extends Thread {
	private ShareData sd; // 공통으로 사용할 객체의 참조값이 저장될 변수 선언
	
	// 방법1 ==> setter를 이용하여 공통으로 사용할 객체 초기화하기
	public void setSd(ShareData sd) {
		this.sd = sd;
	}
	
	@Override
	public void run() {
		
		/*
		 * 원주율 = (1/1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 ... ) * 4
		 * 
		 * 		분모만 보면 규칙성? 1 - 3 + 5 - 7 + 9 - 11 ...
		 * 
		 * 		2로 나눈 몫         ? 0 - 1 + 2 - 3 + 4 -  5 ...
		 */
		
		double sum = 0.0;
		
		for(int i=1; i<=2_000_000_000; i+=2) {
			if( (i/2) % 2 == 0 ) { // 몫이 짝수일 때
				sum += (1.0 / i);
			}else { // 몫이 홀수일 때
				sum -= (1.0 / i);
			}
		}
		
		sd.result = sum * 4; // 계산 결과를 공통객체의 result 변수에 저장한다.
		sd.isOk = true; // 계산이 완료됨을 설정한다.
		
	}
}

// 계산이 완료되면 계산된 원주율을 출력하는 쓰레드
class PrintPIThread extends Thread {
	private ShareData sd; // 공통으로 사용할 객체의 참조값이 저장될 변수 선언
	
	// 방법2 ==> 생성자를 이용하여 공통으로 사용할 객체 초기화하기
	public PrintPIThread(ShareData sd) {
		this.sd = sd;
	}
	
	@Override
	public void run() {
		while(true) {
			if(sd.isOk == true) { // 계산이 완료되면 반복문을 빠져 나온다.
				break;
			}
		}
		// 계산된 결과를 출력한다.
		System.out.println();
		System.out.println("원주율 계산 결과 : " + sd.result);
		System.out.println("Math.PI : " + Math.PI);
	}
}

// 원주율을 관리하는 객체 (공통으로 사용할 객체)
class ShareData {
	public double result; // 계산된 원주율이 저장될 변수
	public volatile boolean isOk; // 계산이 완료되었는지 여부를 나타내는 변수
	
	// volatile ==> CPU의 각 코어에 캐시가 있는데 이 캐시를 사용하지 않고 직접 메모리에서 데이터값을 입출력하도록 한다.
}



[ThreadTest15.java]

package kr.or.ddit.basic;

public class ThreadTest15 {

	public static void main(String[] args) {
		
		ShareObject sObj = new ShareObject(); // 공통 객체 생성
		
		TestThread th1 = new TestThread("test1", sObj);
		TestThread th2 = new TestThread("test2", sObj);
		
		th1.start();
		th2.start();
		
	}

}

class TestThread extends Thread {
	
	private ShareObject sObj;
	
	public TestThread(String name, ShareObject sObj) {
		super(name); // 쓰레드의 name 설정
		this.sObj = sObj;
	}

	@Override
	public void run() {
		for(int i=0; i<10; i++) {
			sObj.add();
		}
	}
	
}

// 공통으로 사용할 객체
class ShareObject {
	
	private int sum = 0;
	
	//public synchronized void add() { // 방법1 ==> 메서드에 동기화 설정을 한다.
	public void add() {
		synchronized (this) { // 방법2 == 동기화 블럭을 이용하여 설정한다.
			int n = sum;
			
			n += 10; // 10 증가
			
			sum = n;
			
			System.out.println(Thread.currentThread().getName() + " 합계 : " + sum);
		}
	}
	
}

'대덕인재개발원_자바기반 애플리케이션' 카테고리의 다른 글

230905_입출력 1  (0) 2023.09.04
230904_스레드 5  (0) 2023.09.04
230831_스레드 3  (0) 2023.08.31
230830_스레드 2  (0) 2023.08.29
230829_스레드 1  (0) 2023.08.29