2020.10.30 고급자바 Thread - stop 메소드 , 여러쓰레드가 같은 데이터를 공유 , 동기화

 stop 메소드 대신 


package kr.or.ddit.basic;


/*

 * Thread 의 stop() 메소드를 호출하면 쓰레드가 바로 멈춘다. 

 * 이때 사용하던 자원을 정리하지 못하고 프로그램이 종료되어 

 * 나중에 실행되는프로그램에 영향을 줄 수 있다. 

 * 그래서 stop () 메서드는 비추천으로 되어 있다. 

 * 

 * 

 * 

 */


public class ThreadTest14 {


public static void main(String[] args) {


/*

ThreadStopTest1 th1 = new ThreadStopTest1();

th1.start();


try {

Thread.sleep(1000);

} catch (Exception e) {

// TODO: handle exception

}

// th1.stop();

th1.setStop(true);

   */

//interrupt() 메서드를 이용한 쓰레드 멈추기 

ThreadStopTest2 th2 = new ThreadStopTest2(); 

th2.start();

try {

Thread.sleep(1000);

} catch (Exception e) {

// TODO: handle exception

}

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()메서드를 이용하는 방법

// 쓰레드가 일시정지한 상태에서 interrupt() 메서드가 호출되면 

// 해당 쓰레드는 일시정지 상태에서 풀려나고 동시에 InterruptedException 을 발생시킨다. 

try {


while (true) {

System.out.println("실행중");

Thread.sleep(1);

}


} catch (InterruptedException e) {


}

*/

//방법 2) 

while(true) { 

System.out.println("Thread 실행중..");

//interrupt() 메서드가 호출되었는지 검사한다. 

/*// 검사방법 1) 쓰레드의 인스턴스 메서드인 isInterrupted() 메서드를 이용한다. 

// isInterrupted() 메서드는 interrupt() 메서드가 호출되면 

// isInterrupted() 메서드는 interrupt() 메서드가 호출되면  true 를 반환한다. 

if(this.isInterrupted()) { 

break; 

}

}*/

// 검사방법 2) 쓰레드의 정적메서드인 interrupted() 메서드 이용하기 

// interrupted() 메서드 ==> interrupt() 메서드가 호출되면 true 를 반환한다. 

if(Thread.interrupted()) {

break; 

}

}

System.out.println("자원정리...............");

System.out.println("쓰레드종료...............");


}


}


-----------------------------------------------------------------------------------------------------

여러쓰레드가 같은 데이터를 공유


package kr.or.ddit.basic;

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

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

public class ThreadTest15 {

public static void main(String[] args) {
// 공통으로 사용할 객체를 먼저 생성 
ShareData sd = new ShareData();

//쓰레드 객체를 생성한다. 공통으로 사용할 객체를 쓰레드에 주입한다. 
PrintPIThread printPi = new PrintPIThread(sd);
CalcPIThread calcPi = new CalcPIThread(); 
calcPi.setSd(sd); 
System.out.println("계산 시작 ");
calcPi.start();
printPi.start();
}

}


//원주율을 계산하는 쓰레드 
class CalcPIThread extends Thread {
private ShareData sd; 
/*생성자 
* public CalcPIThread( ShareData sd) {
this.sd = sd;
}*/
//생성자를 안만드려면 이렇게 하면 된다. 
public void setSd(ShareData sd) { 
this.sd = sd; 
//
@Override
public void run() {
/*
* 원주율 = (1/1 - 1/3 + 1/5 - 1/7 + 1/9 - ...... ) * 4 ; 
*
* 1, - 3, 5, - 7, 9 
* 0    1  2    3  4 
* 2로 나눈것의 홀수 : - 
* 2로 나눈것의 짝수 : + 
*/
double sum = 0.0 ; 
for(int i = 1 ; i <= 2000000000 ; 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; //캐시에다가 가져다 놓고 캐시에서 비교를 한다...
//다른 쓰레드가 변경을 해줬는데도 캐시에서가져온 데이터만 비교하기 때문에 결과가 안나올 수 있다. 
// valotile 을 붙이면 -> 무조건 메모리에서 읽어와라라는 뜻. 
}
}
System.out.println("결과 : " + sd.result);
System.out.println("PI : " + Math.PI);
}
}







//공통으로 사용할 클래스 ==> 원주율을 관리하는 클래스 

class ShareData { 
public double result;         //계산된 원주율이 저장될 변수 
//volatile ==> cpu 하고의 속도 차이 줄이기 위해 램 (메모리 ) 에서데이터를 캐시에 저장을 해놓고 cpu 가
//사용을 한다. 
// 캐시 : 서버에 있는 데이터와 화면에 있는 데이터중에 변경된거만 보여준다. ( 내컴퓨터에서 읽어서 보여줌) 
public volatile  boolean isOk ;  //계산이 완료되었는지 여부를 나타내는 변수  
//volatile : 이 키워드가 붙은 변수는 컴파일러의 최적화 대상에서 제외된다. 
// 캐쉬에서 가져와서 비교하는 것이 아니라 메모리에서 비교해라 라는 뜻.
// 즉, 값이 변경되는 즉시 변수에 적용시킨다. 
}



-----------------------------------------------------------------------------------------------------
제어가 어디에 있냐에 따라 출력되는 데이터가 다르다 


package kr.or.ddit.basic;

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 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 void add() { 
int n = sum ; 
n += 10 ; 
sum = n;
System.out.println(Thread.currentThread().getName() + "합계 :" + sum);
// 제어가 어떤시점에 어디 쓰레드로 변경했는지에 따라서 데이터가 이상하게 나올수 있다. 결과는 200으로 나오지만
}
}



-----------------------------------------------------------------------------------------------------

동기화 


package kr.or.ddit.basic;


//은행의 입출금을 쓰레드로 처리하는 예제 
//(동기화 처리 예제)


public class ThreadTest17 {
private int balance; //잔액이 저장될 변수
public int getBalance() {
return balance;
}




public void setBalance(int balance) {
this.balance = balance;
}


//입금하는 메서드 
public void deposit (int money) { 
balance += money ; 
}
// 출금하는 메서드  출금성공 : true , 출금 실패 : false 를 반환 
public /*synchronized */boolean withdraw(int money) { // 첫번쨰는 동기화 메소드 
synchronized(this) { //동기화 블럭 
if(balance >= money) {
for(int i = 1 ; i <= 100000000 ; i++ ) {}  // 시간 지연용 
balance -= money; 
System.out.println("메서드 안에서 balance : " + getBalance());
return true; 
}else { 
return false; 
}
}
}



public static void main(String[] args) {
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();
}

}




댓글