/*
10마리의 말들이 경주하는 프로그램을 작성하시오.
말은 Horse라는 이름의 쓰레드 클래스로 작성하는데
이 클래스는 말이름(String), 등수(int), 현재위치(int)를 멤버변수로 갖는다.
그리고 이 클래스에는 등수를 오름차순으로 정렬할 수 있는 내부 정렬 기준이 있다. (Compareable 인터페이스 구현)
경기 구간은 1 ~ 50구간으로 되어 있다.
경기가 끝나면 등수 순으로 출력한다.
경기 중에는 중간 중간에 각 말들의 위치를 아래와 같이 나타내 준다.
예)
말이름1 : --->---------------------------------------- (50개)
말이름2 : ------>------------------------------------- (50개)
...
말이름10 : ---->--------------------------------------- (50개)
50구간째가 '>'가 되면 끝남
*/
public class ThreadTest13 {
public static void main(String[] args) {
Horse[] horses = new Horse[] {
new Horse("1번말"),
new Horse("2번말"),
new Horse("3번말"),
new Horse("4번말"),
new Horse("5번말"),
new Horse("6번말"),
new Horse("7번말"),
new Horse("8번말"),
new Horse("9번말"),
new Horse("10번말")
};
//경주 시작
for(Horse hs : horses) {
hs.start();
}
//2초에 한번씩
outer : while(true) {
for(Horse hs : horses) {
System.out.print(hs.name);
System.out.println(hs.race);
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//모든 쓰레드가 끝났을 때 break
int countThread = 0;
for(Horse hs : horses) {
if(hs.getState() == Thread.State.TERMINATED) {
countThread++;
}
if(countThread == 10) {
break outer;
}
}
System.out.println("=====================================================");
}
//랭크 나타내기
System.out.println(Horse.setRank);
}
}
class Horse extends Thread implements Comparable<Horse> {
public static ArrayList<String> setRank = new ArrayList<>();
public String name;
private int rank;
private int now;
char[] race = new char[49];
//생성자
public Horse(String name) {
this.name = name;
rank = 0;
now = 0;
//50구간에서 한칸씩 증가
for(int i = 0; i < 49; i++) {
race[i] = '-';
}
}
//비교 - 등수를 기준으로 오름차순
@Override
public int compareTo(Horse h) {
return Integer.compare(rank, h.rank);
}
//달리는 메서드
@Override
public void run() {
//현재 위치 나타내기
for(int i = 0; i < 49; i++) {
if(now == i) {
race[i] = '>';
//값을 묶기
try {
Thread.sleep((int)(Math.random() * 500));
} catch (InterruptedException e) {
e.printStackTrace();
}
now++;
}
// System.out.print(name + " : ");
// System.out.println(race);
race[i] = '-';
}
//끝난 순서대로 이름 집어넣기
setRank.add(name);
// System.out.println(setRank);
}
}
Thread의 stop()메서드를 호출하면 쓰레드가 바로 멈춘다.
이 때 사용하던 자원을 정리하지 못하고 프로그램이 종료되어
이 후에 실행되는 프로그램에 영향을 줄 수 있다.
그래서 stop()메서드는 비추천으로 되어 있다.
stop()메서드는 비추천됨
sleep() => 주어진 쓰레드가 일시정지됨
일시정지 상태의 쓰레드는 interrupt()를 만나면
interruptedException을 발생하며 빠져나옴
1.13 쓰레드의 동기화 - synchronized
public static void main(String[] args) {
// ThreadStopTest1 th1 = new ThreadStopTest1();
// th1.start();
//
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// //th1.setStop(true);
// th1.stop();
ThreadStopTest2 th2 = new ThreadStopTest2();
th2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
th2.interrupt();
}
}
// 쓰레드를 멈추게 하는 연습용 쓰레드
class ThreadStopTest1 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 ThreadStopTest2 extends Thread{
@Override
public void run() {
//방법1 ==> interrupt()메서드와 sleep()메서드를 이용하는 방법
try {
while(true) {
System.out.println("실행 중");
Thread.sleep(1);
// 일시정지 상태에서 interrupt()메서드가 실행되면 interruptedException이 발생한다.
// 그러면 catch문으로 빠져나온다.
}
} catch (InterruptedException e) {
}
//방법2 ==> interrupt()메서드가 호출되었는지 검사하는 방법
while(true) {
System.out.println("Thread 실행중...");
// interrupt() 메서드가 호출되었는지 여부를 검사한다.
// 검사방법1) ==> Thread의 인스턴스 메서드인 isInterrupted()를 이용하여 검사하기
// - isInterrupted()메서드 interrupt()메서드가 호출되면 true를 반환한다.
//
//if(this.isInterrupted()) {
// break;
//}
// 검사방법2) ==> Thread의 정적메서드인 interrupted()메서드를 이용하여 검사하기
// ==> interrupt()메서드가 호출되면 true를 반환한다.
if(Thread.interrupted()) {
break;
}
}
System.out.println("자원정리 중...");
System.out.println("쓰레드 종료...");
}
}
// 쓰레드에서 객체를 공통으로 사용하는 예제
/*
원주율(PI)를 계산하는 쓰레드와 계산된 원주율을 출력하는 쓰레드가 있다.
원주율을 저장하는 객체가 필요하다.
이 객체를 두 쓰레드가 공통으로 사용해서 처리한다.
*/
public class ThreadTest15 {
public static void main(String[] args) {
//공통으로 사용할 객체 생성
ShareData sd = new ShareData();
//쓰레드 객체를 생성하고 공통으로 사용할 객체를 쓰레드에 주입한다.
CalcPIThread ct = new CalcPIThread();
ct.setSd(sd);
PrintPIThread pt = new PrintPIThread(sd);
ct.start();
pt.start();
}
}
// 원주율을 관리하는 클래스 작성(공통으로 사용할 클래스)
class ShareData{
public double result; // 계산된 원주율이 저장될 수 있는 변수 선언
public boolean isOk = false; // 계산이 완료되었는지를 나타내는 변수
}
// 원주율을 계산하는 쓰레드
class CalcPIThread extends Thread{
private ShareData sd;
//setter
public void setSd(ShareData sd) {
this.sd = sd;
}
@Override
public void run() {
/*
원주율 = (1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 ....) * 4;
1 - 3 + 5 - 7 + 9 - 11
0 1 2 3 4 5 ==> 2로나눈 몫이 짝수일때는 +, 홀수일때 -
*/
double sum = 0.0;
for(int i = 1; i <= 100000000; i+=2) {
if( (i/2) % 2 == 0 ) { //몫이 짝수인 경우
sum += (1.0/i);
}else {
sum -= (1.0/i);
}
}
sd.result = sum * 4; // 계산이 완료된 값을 공통객체에 저장한다.
sd.isOk = true;
}
}
// 계산이 완료되면 계산된 원주율을 출력하는 쓰레드
class PrintPIThread extends Thread{
private ShareData sd;
//생성자
public PrintPIThread(ShareData sd) {
this.sd = sd;
}
@Override
public void run() {
while(true) {
if(sd.isOk) {
break;
}
Thread.yield();
}
System.out.println();
System.out.println("결과 : " + sd.result);
System.out.println("PI : " + Math.PI);
}
}
public class ThreadTest16 {
public static void main(String[] args) {
ShareObject sObj = new ShareObject();
TestThread th1 = new TestThread("1번 쓰레드", sObj);
TestThread th2 = new TestThread("2번 쓰레드", sObj);
th1.start();
th2.start();
}
}
//공통으로 사용할 클래스
class ShareObject{
private int sum = 0;
// 동기화 처리하기
// public synchronized void add() { //방법1 ==> 메서드에 동기화 설정하기
public void add() {
synchronized (this) { //방법2 ==> 동기화 블럭으로 설정하기
int n = sum; //쓰레드가 제어를 실행할 때 과정을 보려고 풀어서 쓴 것
n += 10;
sum = n;
System.out.println(Thread.currentThread().getName() + " 합계 : " + sum);
}
}
}
class TestThread extends Thread{
private ShareObject sObj;
public TestThread(String name, ShareObject sObj) {
super(name); //쓰레드의 이름 설정
this.sObj = sObj;
}
@Override
public void run() {
for(int i = 1; i <= 10; i++) {
sObj.add();
}
}
}
//은행의 입출금을 쓰레드로 처리하는 예제(동기화 처리 예제)
public class ThreadTest17 {
private int balance; // 잔액이 저장될 변수
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
// 입금하는 메서드
public void deposite(int money) {
balance += money;
}
// 출금하는 메서드 (출금 성공: true, 출금 실패: false 반환)
// public synchronized boolean withdraw(int money) {
public boolean withdraw(int money) {
synchronized (this) {
if(balance >= money) {
for(int i = 1; i <= 100000000; i++) {} //시간 지연용
balance -= money;
System.out.println("메서드 안에서 balance = " + balance);
return true;
}else {
return false;
}
}
}
public static void main(String[] args) {
final ThreadTest17 acount = new ThreadTest17();
acount.setBalance(10000); //잔액을 10000원으로 설정한다.
//익명 구현체로 쓰레드 만들기
Runnable test = new Runnable() {
@Override
public void run() {
boolean result = acount.withdraw(6000); //6000원 출금하기
System.out.println("쓰레드에서 result = " + result + ", balance = " + acount.getBalance());
}
};
//--------------------------------------------------
Thread th1 = new Thread(test);
Thread th2 = new Thread(test);
th1.start();
th2.start();
}
}
Vector, Hashtable 등 예전부터 존재하던 Collection 객체들은 내부에 동기화 처리가 되어있다.
그런데, 최근에 새로 구성된 Collection 객체들은 동기화 처리가 되어있지 않다.
그래서 동기화가 필요한 프로그램에서 이런 Collection들을 사용하려면 동기화 처리를 한 후에 사용해야 한다.
public class ThreadTest18 {
private static Vector vec = new Vector<>();
//동기화 처리가 되지 않은 List
private static ArrayList<Integer> list1 = new ArrayList<>();
//동기화 처리를 한 List
private static List<Integer> list2 = Collections.synchronizedList(new ArrayList<Integer>());
public static void main(String[] args) {
//익명 구현체로 쓰레드 구현
Runnable r = new Runnable() {
@Override
public void run() {
for(int i = 0; i < 10000; i++) {
//vec.add(i);
//list1.add(i);
list2.add(i);
}
}
};
//---------------------------------------------
Thread[] thArr = new Thread[] {
new Thread(r), new Thread(r), new Thread(r),
new Thread(r), new Thread(r)
};
for(Thread th : thArr) {
th.start();
}
for(Thread th : thArr) {
try {
th.join();
} catch (InterruptedException e) {
// TODO: handle exception
}
}
// System.out.println("vec 개수 : " + vec.size());
// System.out.println("list1 개수 : " + list1.size());
System.out.println("list2 개수 : " + list2.size());
}
}