250x250
Notice
Recent Posts
Recent Comments
«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Tags more
Archives
Today
Total
관리 메뉴

개린이 개발노트

국비지원 JAVA(자바) 프로그래밍(Thread, 스레드, 람다, 익명함수, 상태 제어- sleep(), join() ,yield(), Thread동기화synchronized,데몬스레드 ) 본문

국비지원(국비교육) 웹 개발자 과정

국비지원 JAVA(자바) 프로그래밍(Thread, 스레드, 람다, 익명함수, 상태 제어- sleep(), join() ,yield(), Thread동기화synchronized,데몬스레드 )

개린이9999 2022. 12. 6. 09:25
728x90

쓰레드(Thread)( 쓰레드 실행시킬 떄는 .start 이용! )

public void run() {

}

run 메서드도 구현해야함 ↑

숫자가 높을 수록 우선순위가 큼/ (기본설정값 5) 

메인이 끝났다고 무조건 스레드가 끝나는 것은아님

t1.interrupt();  // 정지중인 상태의 대한 스레드만 강제로 예외 발생 시켜서 중지 

.join은 스레드가 종료될때까지 기다리라는 뜻 

Thread.yield(); -> 쓰레드가 동시에 사용될때 하나가 필요없을 떄무의미한 반복시키는 것 (메모리 감소를 위해) 

package 준석;
public class Yt extends Thread{
}-> 스레드 생성

 

 

다중처리 진행인데 앞전의 것을 기다리지 않고 먼저 실행(멀티태스킹한다고 생각)

이클립스하면서 노래를 켜놓으면 음악이 같이 돌아가는  것처럼 여러개를 다중으로 실행시켜주는것.

쓰레드라는 풀을 이용해서 작업할 것을 분산시켰다가 각각의 작업이 끝나면 다시 되돌려줌.

 

package 준석;

public class RunnableImple implements Runnable {

	public void run() {
		System.out.println("Runnable 상속");
		for (int i = 0; i < 50; i++) {
			System.out.println("Runnable:" + i);
		}
	}
}
package 준석;

public class ThreadExtend extends Thread{

	public void run() {					//run 메서드 고정
		System.out.println("Thread 상속");
		for (int i = 0; i < 50; i++) {
			System.out.println("Thread: "+ i);
			
		}
	}
}
package 준석;

public class Sample01 {

	public static void main(String[] args) {

		ThreadExtend t1= new ThreadExtend();
		
		Runnable r= new RunnableImple();	
		
		Thread t2= new Thread(r);
		
		t1.start();								// 쓰레드 실행시킬 떄는 .start 이용! 
		t2.start();									
	}

}

쓰레드 기본 예시 ↑


익명 구현객체로 (1회성, 흔치않음) 

메인 클래스에서 바로 실행

 

package 준석;

public class Sample02 {

	public static void main(String[] args) {

		Thread t1 = new Thread(new Runnable() {
			public void run() {
				System.out.println("t1스레드");
				for (int i = 0; i < 50; i++) {
					System.out.println("t1:"+i);
				}
			}
		});

위의내용과

Runnable r = new Runnable() {
			public void run() {
				System.out.println("t2스레드");
				for (int i = 0; i < 50; i++) {
					System.out.println("t2:"+i);

				}
			}
		};

위의내용 차이 확인하면서

package 준석;

public class Sample02 {

	public static void main(String[] args) {

		Thread t1 = new Thread(new Runnable() {
			public void run() {
				System.out.println("t1스레드");
				for (int i = 0; i < 50; i++) {
					System.out.println("t1:"+i);
				}
			}
		});
		
		
		Runnable r = new Runnable() {
			public void run() {
				System.out.println("t2스레드");
				for (int i = 0; i < 50; i++) {
					System.out.println("t2:"+i);

				}
			}
		};
	
		Thread t2 = new Thread(r);
	
		t1.start();
		t2.start();
	}
}

전체코드 확인 ↑

이 자바 코드는 t1과 t2라는 두 개의 스레드를 만든다. 각 스레드는 메시지를 출력한 다음 일련의 번호를 출력하며, 각 스레드는 자체 일련의 번호를 출력한다. 스레드는 각 스레드에서 start() 메서드를 호출하여 시작된다.

 


람다로 쓰레드(별도 클래스 필요x)

	Runnable r= ()-> {									//람다구현
		System.out.println("t2 스레드"); 		
	for (int i = 0; i <50; i++) {
		System.out.println("t2: "+i);
			}
		};

람다 구현 ↑

package 준석;

public class Sample03 {

	public static void main(String[] args) {

		
		Thread t1 = new Thread(() -> {
			System.out.println("t1 스레드");
			for (int i = 0; i < 50; i++) {
				System.out.println("t1: "+i);

			}
		});
	
	Runnable r= ()-> {									//람다구현
		System.out.println("t2 스레드"); 		
	for (int i = 0; i <50; i++) {
		System.out.println("t2: "+i);
			}
		};
		
		Thread t2 = new Thread(r);
		t1.start();
		t2.start();
	}

}

 

전체!! 위와 아래 구분하며 비교

위 코드는 람다 식과 실행 가능 개체를 각각 사용하여 t1과 t2라는 두 개의 스레드를 만든다. 두 스레드는 메시지를 출력하는 루프와 루프 변수 i의 값을 실행한다. 스레드가 시작되면 스레드가 동시에 실행되고 두 스레드의 메시지가 출력에 인터리브된다. 

 

Thread 사용할 때 우선순위 결정가능

파일과 메세지 전송할떄, ( 파일 전송중입니다-> 파일 ->파일전송이완료되었습니다) 

	t1.setPriority(10); // 숫자가 높을 수록 우선순위가 큼 
		t2.setPriority(1);
		
		t1.start();
		t2.start();
	}

}

숫자가 높을 수록 우선순위가 큼으로 t1이 다 끝나고 t2가 시작됨  ↑

기본 설정값 5로 설정되어있음 

t1.setPriority(Thread.MAX_PRIORITY); // 상수 호출 max
t2.setPriority(Thread.MIN_PRIORITY);
				Thread.NORM_PRIORITY	기본값(5)

MAX=10, min = 1 , norm 기본값 (5) 




JAVA 스레드(thread) 상태 제어(1) - sleep(),  join() ,yield()

상태 제어  

sleep이 try catch문 강요 ↓

t1.interrupt();  // 정지중인 상태의 대한 스레드만 강제로 예외 발생 시켜서 중지 

sleep이 try catch문(try catch 문에서 finally 잊지말것!) 이용한 스레드(Thread) 

package 준석;

public class Sample04 {

	public static void main(String[] args) {

		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i <10; i++) {
					System.out.println("t1: "+ i);
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		});
	
		t1.start();
	}
}

t1.interrupt();  // 정지중인 상태의 대한 스레드만 강제로 예외 발생 시켜서 중지 

 

1초마다 실행!
위에꺼가 1초의 대기시간이 있어서 정지상태가 되어서 10초가 되면 interrupt 가 되면 정지

interrupt는 정지중인 상태의 대한 스레드// 위같은 경우는 t1 스레드가 1초부터 시작해서 10초(sleep(1000))일때 대기중일 때 밑에 인터럽트가 10초(sleep(10000)에서 발생하므로  정지됨// interrupt가 없다면 while(true)로 인해 무한반복됨

 

전체예시 ↓

package 준석;

public class Sample05 {

	public static void main(String[] args) {
		Thread t1 = new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					int i = 1;
					while (true) {
						System.out.println("t1: " + i);
						Thread.sleep(1000);
						i++;
					}
				} catch (Exception e) {

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

		t1.start();

		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		t1.interrupt(); 	// 강제로 예외 발생 시켜서 중지 
	}

}

package 준석;

public class Sum extends Thread {

	int sum = 0;

	public void run() {
		for (int i = 0; i < 100; i++) {
			sum += i;
		}
	}

}
package 준석;

public class Sample06 {

	public static void main(String[] args) {

		Sum t1 = new Sum();
		Sum t2 = new Sum();
	
		t1.start();
		t2.start();
		System.out.println(t1.sum+t2.sum);
	}

}

값:0 

이 나오는 이유 .. join 문 안써서..? 

package 준석;

public class Sample06 {

	public static void main(String[] args) {

		Sum t1 = new Sum();
		Sum t2 = new Sum();
	
		t1.start();
		t2.start();
	
	try {
		t1.join();
		t2.join();				// .join은 스레드가 종료될떄까지 기다리라는 뜻 
	} catch (Exception e) {
	}
	System.out.println(t1.sum+t2.sum);

	}

}

.join&nbsp; 써서 결과값

 

 

JAVA 스레드(thread) 상태 제어 yield()



JAVA 스레드(thread)  synchronized

동기화란?

public synchronized void 메서드 이름() { 
 한개 스레드만 실행 }

 

public void 메서드 이름(){
여러 스레드 실행가능
synchronized (공유객체){
 한개 스레드만 실행 
      }
}
 

 

공유자원 썼을 때 만 사용가능

한번에 한개의 스레드만 공유자원에 접근하도록 잠그고,

다른 스레드는 진행중인 작업을 간섭하지 못하게함 

 

동기화 안시킨 상태 ↓

package 준석;

public class SmartPhoneGame {

	private int level;

	public int getLevel() {
		return level;
	}

	public void increaseLevel() {

		while (true) {
			this.level++;
			try {
				Thread.sleep(1000);
			} catch (Exception e) {
			}
			System.out.println(Thread.currentThread().getName() + "lv: " + this.level);

			if (this.level % 10 == 0) {
				break;

			}
		}
	}
}
package 준석;

public class Player extends Thread {
   
   private SmartPhoneGame game;

   public void setGame(SmartPhoneGame game) {
      this.setName("Player");	// 스레드 이름 설정 
      this.game = game;
   }
   
   public void run() {
      game.increaseLevel();
   }
   
   
   

}
package 준석;

public class Player2 extends Thread {
   
   private SmartPhoneGame game;

   public void setGame(SmartPhoneGame game) {
      this.setName("Player2");
      this.game = game;
   }
   
   public void run() {
      game.increaseLevel();
   }
   
   
   

}

동기화 안시킨 상태 ↑  동일한 객체( SmartPhoneGame game = new SmartPhoneGame();)
로 만들다 보니까 원하던 형태로 안만들어짐 (캐릭터가 하나인데 컨트롤 하는 사람이 두 명이라 이런식으로 증가됨..원래는 1,2,3,4,.가 되야하는데 2,4,6,8로 됨) 

 

동기화 시킨  상태 ↓

Smartphone~클래스에 synchronized 추가!!

-> public synchronized void increaseLevel() {~~~

package 준석;

public class SmartPhoneGame {

	private int level;

	public int getLevel() {
		return level;
	}

	public synchronized void increaseLevel() {

		while (true) {
			this.level++;
			try {
				Thread.sleep(1000);
			} catch (Exception e) {
			}
			System.out.println(Thread.currentThread().getName() + "lv: " + this.level);

			if (this.level % 10 == 0) {
				break;

			}
		}
	}
}

결과값:

Playerlv: 1
Playerlv: 2
Playerlv: 3
Playerlv: 4
Playerlv: 5
Playerlv: 6
Playerlv: 7
Playerlv: 8
Playerlv: 9
Playerlv: 10
Player2lv: 11
Player2lv: 12
Player2lv: 13
Player2lv: 14
Player2lv: 15
Player2lv: 16

 

위에이어서..

 

Thread 스레드간 협업

wait() -> 실행중인 스레드Thread 대기

notify() -> 대기중인 스레드 Thread 실행 (단, 선택 불가능= 스레드가 열개가 있었을 때 한개만 실행이 되고 나머지 9개는 대기상태 일 때 9개중에 하나를 실행 시키고 싶을 때 notify를 통해서 실행시킬 수 있지만 어떤 특정 스레드를 실행 시킬 지 선택할 수 없다는 뜻)

notifyAll()-> 모든 대기중인 스레드를 실행 

 

notifyAll() 사용  ↓

package 준석;

public class SmartPhoneGame {

	private int level;

	public int getLevel() {
		return level;
	}

	public synchronized void increaseLevel() {

		while (true) {
			this.level++;
			try {
				Thread.sleep(1000);
			} catch (Exception e) {
			}
			System.out.println(Thread.currentThread().getName() + "lv: " + this.level);

			if (this.level==5) {
				notifyAll();
				try {
					wait();
				} catch (Exception e) {
				
				}
			}
			
			
			if (this.level % 10 == 0) {
				break;

			}
		}
	}
}

결과값 

Playerlv: 1
Playerlv: 2
Playerlv: 3
Playerlv: 4
Playerlv: 5
Player2lv: 6
Player2lv: 7
Player2lv: 8
Player2lv: 9
Player2lv: 10


package 준석;

public class WorkObject {

	public synchronized void methodA() {
		System.out.println("methodA 실행");

		notify();

		try {
			wait();
		} catch (Exception e) {

		}
	}

	public synchronized void methodB() {
		System.out.println("methodB 실행");

		notify();

		try {
			wait();
		} catch (Exception e) {

		}
	}

}
package 준석;

public class ThreadA extends Thread{

   private WorkObject workobject;

   public ThreadA(WorkObject workobject) {
      this.workobject = workobject;
   }
   
   public void run() {
      for(int i = 0; i<10; i++) {
         workobject.methodA();
      }
   }

}
package 준석;

public class ThreadB extends Thread{

   private WorkObject workobject;

   public ThreadB(WorkObject workobject) {
      this.workobject = workobject;
   }
   
   public void run() {
      for(int i = 0; i<10; i++) {
         workobject.methodB();
      }
   }

}
package 준석;

public class Sample08 {

	public static void main(String[] args) {

		WorkObject wo = new WorkObject();

		Thread threadA = new ThreadA(wo);
		Thread threadB = new ThreadB(wo);

		threadA.start();
		threadB.start();
	}

}

결과값

 


interrupt 가 아니라 따로 변수를 설정해서 지금같은 경우는

boolean을 통해서(예시일 뿐) 중지를 하게끔 함 ↓

interrupt 같은 거사용하려면 sleep 같은거 필요함

+throw 개념 

package 준석;

public class RunThread extends Thread {

	boolean stop;

	public void run() {
		while (!stop) {
			System.out.println("스레드 실행중");
		}
		
		System.out.println("스레드 종료");
	}
}
package 준석;

public class Sample09 {

	public static void main(String[] args) throws InterruptedException {

		RunThread t= new RunThread();
		
		t.start();
		
		Thread.sleep(3000); // 여기서 발생되면 InterruptedException로 떠념거라! == throws InterruptedException
		t.stop =true;
		
	}

}

내 통장이 있는데 부모님이 용돈을 주는 상황,

나는 그 돈을 다빼서 쓴다 -> 그러다 잔고가 0원이 되면

부모님이 또 용돈을 주심 ->반복 synchronized 이용

통장에 부모님(+)과 내(-)가 동시에 MONEY에 이루어지게 되면 애매한 경우가 생김



데몬 스레드

스레드를 보조하는 기능 

일반스레드가 종료되면 데몬스레드도 종료됨 

데몬 스레드 사용하려면 .start 전에 사용

t1.setDaemon(true); 이런식으로 

package 스레드2;

public class Demon extends Thread {

	public void run() {

		while (true) {
			System.out.println(getName());
			try {
				sleep(1000);
			} catch (Exception e) {

			}
		}
	}
}
package 스레드2;

public class Sample01 {

	public static void main(String[] args) {

		Demon t1 = new Demon();
		Demon t2 = new Demon();

		t1.setDaemon(true);
		t2.setDaemon(true);

		t1.start();
		t2.start();

		try {
			Thread.sleep(5000);
		} catch (Exception e) {
		
		}
		
		System.out.println("main 종료");
	}

}

 

데몬 스레드로 자동저장 기능 만들기

package 스레드2;

public class AutoSave extends Thread {

	public void save() {
		System.out.println("자동 저장");
	}

	public void run() {
		while (true) {
			try {
				sleep(1000);
			} catch (Exception e) {

			}

			save();
		}
	}

}
import 스레드2.AutoSave;

public class Sample02 {

	public static void main(String[] args) {

		AutoSave as = new AutoSave();

		as.setDaemon(true);

		as.start();

		System.out.println("문서작성 시작");

		try {
			Thread.sleep(5000);
		} catch (Exception e) {
		}
		System.out.println("문서작성 종료");
	}

}

결과값: 

문서작성 시작
자동 저장
자동 저장
자동 저장
자동 저장
문서작성 종료


스레드 그룹 (많이 쓰이는 것은 아님)

package 스레드2;

public class MyThread extends Thread {

	MyThread(ThreadGroup group, String name) {
		super(group, name);
	}

	public void run() {
		while (true) {
			System.out.println(getName());
			try {
				sleep(500);
			} catch (Exception e) {
				break;
			}
		}
			System.out.println(getName()+"종료");
		
	}
}
package 스레드2;

public class Sample03 {

	public static void main(String[] args) {
		ThreadGroup group = new ThreadGroup("Group1");

		MyThread t1 = new MyThread(group, "first");
		MyThread t2 = new MyThread(group, "second");
		MyThread t3 = new MyThread(group, "third");
	
		t1.start();
		t2.start();
		t3.start();
		
		try {
			Thread.sleep(3000);
		} catch (Exception e) {
			// TODO: handle exception
		}
			group.interrupt(); // \MyThread가 sleep(500);이고 Thread.sleep(3000);이기 떄문에 6초에서 interrupt 발생
	}
}

group.interrupt(); // \MyThread가 sleep(500);(0.5초)이고 Thread.sleep(3000)(3초);이기 떄문에 3초에서 interrupt 발생


게임 

내 캐릭터 - 몬스터 

스레드를 안쓰면 턴제 공격밖에 안됨.

쓰레드를 쓰면 

ex)

내캐릭터 1초마다 떄림, 몬스터3초마다 떄림

하면 3초마다 동시에 때리게끔 만들수있음


사용자랑 컴퓨터랑 전투

기본 데미지 1~10;

10%확률로 스킬 사용 (데미지 30)

체력 둘다 100;

공격 쿨타임 1~3초

 

체력 0이되면 종료 


package 게임;

public abstract class User {
   
   String userID;
   int hp;

}
package 게임;

public interface Msg {

	void attackMsg(int dam); // 공격시 나타나는 메시지
	void useSkillMsg();	// 10% 확률로 스킬 사용시 나타나는 메시지
	void hpMsg(); // 남은 체력 알려주는 메시지
	void endMsg(); // 종료 시 나타는 메시지 

}
package 게임;

public class Charactor extends User implements Msg {
   
   public Charactor(String userID, int hp) {
      this.userID = userID;
      this.hp = hp;
   }
   

   @Override
   public void attackMsg(int dmg) {
      System.out.println(this.userID + "가 상대에게" + dmg + "의 데미지를 입힙니다.");
      
   }

   @Override
   public void useSkillMsg() {
      System.out.println(this.userID + "가 상대에게 30의 스킬 데미지를 입힙니다.");
      
   }

   @Override
   public void hpMsg() {
      System.out.println("남은 체력 : " + this.hp);
      
   }

   @Override
   public void endMsg() {
      System.out.println(this.userID + " 승리");
      
   }
   
   

}
package 게임;

public class PlayUser extends Thread {
   
   private Charactor user;
   private Charactor com;
   
   public PlayUser(Charactor user, Charactor com) {
      this.user = user;
      this.com = com;
   }
   
   public void run() {
      int damage;
      int coolTime;
      
      try {
         while(true) {
            coolTime = ((int)(Math.random() *3) +1 ) * 1000;
            Thread.sleep(coolTime);
            
            if((int)(Math.random()*10) == 4) {
               user.useSkillMsg();
               com.hp -= 10;
            } else {
               damage = (int)(Math.random() * 10) +1;
               user.attackMsg(damage);
               com.hp -= damage;
            }
            
            if(com.hp <= 0) {
               user.endMsg();
               System.exit(0);
            }
            
            System.out.println(com.userID + "의 남은 체력 : " + com.hp);
         }
      } catch(Exception e) {
         
      }
   }
   
   

}
package 게임;

public class PlayCom extends Thread {
	 	private Charactor user;
	 	private Charactor com;
	   
	   public PlayCom(Charactor user, Charactor com) {
	      this.user = user;
	      this.com = com;
	   }
	   
	   public void run() {
	      int damage;
	      int coolTime;
	      
	      try {
	         while(true) {
	            coolTime = ((int)(Math.random() *3) +1 ) * 1000;
	            Thread.sleep(coolTime);
	            
	            if((int)(Math.random()*10) == 4) {
	               com.useSkillMsg();
	               user.hp -= 10;
	            } else {
	               damage = (int)(Math.random() * 10) +1;
	               com.attackMsg(damage);
	               user.hp -= damage;
	            }
	            
	            if(user.hp <= 0) {
	               com.endMsg();
	               System.exit(0);
	            }
	            
	            System.out.println(user.userID + "의 남은 체력 : " + user.hp);
	         }
	      } catch(Exception e) {
	         
	      }
	   }
	   

}
package 게임;

import java.util.Scanner;

public class Main {

   public static void main(String[] args) {
      
      Scanner sc = new Scanner(System.in);
      String userID;
      
      System.out.print("유저 아이디 입력 : ");
      userID = sc.next();
      
      Charactor user = new Charactor(userID, 100);
      Charactor com = new Charactor("com", 100);
      
      PlayUser playuser = new PlayUser(user, com);
      PlayCom playcom = new PlayCom(user, com);
      
      playuser.start();
      playcom.start();

   }

}

 

728x90