무작정 개발.Vlog

[JAVA+국비교육] Thread

by 무작정 개발
반응형
2022.01.11(16일 차)

오늘은 java의 꽃이라는 Thread를 배운다. 강사님도 시작하기 전에 앞서 어렵다고 말씀하셨는데 엄청 중요하다고

강조하셨다.

 

 

오늘의 수업 내용

 

Thread (스레드)

스레드는 프로세스 내부에서 실행되는 명령의 모임이고, 단일 스레드와 다중 스레드로 나뉜다.

 

(1) 단일 스레드

  • main 메서드만 이용하여 프로그램을 작성
  •  main 메서드가 종료되면 프로그램도 종료
  • 동시에 명령을 실행할 수 없음

(2) 다중 스레드

  • main 메서드와 다른 메서드에서도 동시에 명령 가능
  • 모든 스레드가 종료되어야지만 프로그램도 종료
  • 다중 스레드를 사용하는 방법에는 Thread 클래스 사용, Runnable 인터페이스 사용, 총 2가지 방법이 존재

 - Thread 제어

    => start() 메서드 : Thread 실행 - 자주 씀

    => stop() 메서드 : Thread 중지

    => destroy() 메서드 : Thread 소멸 

    => sleep() 메서드 : 1/1000초 단위로 실행 속도를 조절할 수 있다. - 자주 씀

    => suspend() 메서드 : 스레드를 일시 정지 - wait() 메서드

    => resume() 메서드 : suspend() 메서드로 중지된 스레드를 다시 실행한다. - notify() 메서드 


Thread 클래스를 사용

package com.day15;
//Thread(스레드)- 클래스로 Thread를 만드는 방법

// 일반 클래스인데 이 클래스에 Thread의 기능을 넣어줄거다.
// Thread를 상속 받는다. 
class MyThread1 extends Thread { // 부모꺼는 내꺼다.(자식이 부모꺼 사용 가능)
	
	private int num;
	private String name;
	
	//생성자를 사용해서 초기화
	public MyThread1(int num, String name) {
		
		this.num = num;
		this.name = name;
	}
	
	
	//Thread는 반드시 run을 오버라이드해야함 - 오른쪽 누르고 소스 - 오버라이드 - run()선택
	
	@Override
	public void run() {	//(4) t1이 먼저 와서 스레드를 만듬(Thread-0)만듬. 99까지 찍고 (6) t2가 올라와서 스레드 만듬
		
		//스레드 메서드(java의 VM이 호출) - 무조건 호출하는 건아니고 start 명령어를 줘야함 star명령어는 main절에서 씀
		int i=0;
		
		while(i<num) {			//클래스이름
			System.out.println(this.getName() + ":" + name + i); // getName : 스레드의 이름을 보여줌
			i++;
			
			
			// try catch를 써야 번갈아가면서 멀티태스팅을 함. 안쓰면 위의 주석 처럼 움직임.(t1끝나고 t2)
			// 스레드1이 0.01초 쉬는동안  스레드2가 실행된다.스레드2가 쉬는동안 스레드1 이 수행.
			try {
				sleep(100); // 0.01초 쉬어 라는 뜻 - 스레드는 sleep이 반드시 필요하다.필수!!!!!
				
			} catch (Exception e) {
				
			}
		}
		
		
	}
	
}


public class Test1 {
						//main절도 스레드다 - main스레드
	public static void main(String[] args) {
		
		System.out.println("main 시작...");// 실행순서 1
		
		MyThread1 t1 = new MyThread1(100, "첫번째 : ");// 실행순서 2
		MyThread1 t2 = new MyThread1(200, "두번째 : ");// 실행순서 2
		
		//스레드는 만들었다고 끝나는게 아니고 start를 해줘야함
		t1.start();// 실행순서3 위로 올라간다
		t2.start();// 실행순서5 위로 올라간다
		
		
		System.out.println("main 종료...");

	}

}

1
1
2
2
3
3

먼저 결과를 보면 main시작, main종료가 출력되고, Thread0, Thread1이 번갈아가면서 실행된다. Thread0은 99까지

찍히고, 그 이후에는 Thread1만 199까지 출력되는 것을 볼 수 있다. 

 

extends를 사용하여 Thread클래스를 상복받아 스레드의 기능을 사용할 수 있게 만들고. 스레드는 run메서드는 반드시 

Override(오버라이드) 해야 한다.

 

또한 스레드에는 반드시 sleep이 필요. sleep은 쉬어가라는 뜻이다.  1000 = 1초 -> sleep(1000) = 1초 쉬어라


Runnable 인터페이스를 이용한 스레드

package com.day15;
//Thread(스레드)- java.lang 패키지의 Runnable 인터페이스를 사용하여 스레드 만드는 방법 



//인터페이스 만들면 오버라이드 해줘야함
class MyThread2 implements Runnable {
	
	private int num;
	private String name;
	
	public MyThread2(int num, String name) {
		
		this.num = num;
		this.name = name;
	}

	@Override
	public void run() {
		
		int i=0;
		
		while(i<num) {
			
			//인터페이스에는 getName이 없다. 쓰레드에는 있지만
			System.out.println(name + ":" + i);
			i++;
			
			
			//스레드일때는 - sleep / 인터페이스(Runnable)일때는 Thread.sleep
			try {
				Thread.sleep(100); // 1000 = 1초
			} catch (Exception e) {
				
			}
		}
		
	}
	
}
public class Test2 {

	public static void main(String[] args) {
		
		System.out.println("main 시작...");
		
		//Runnable을 받은 스레드 객체 생성 방법
		//Runnable은 인터페이스타입이기에 구현 객체를 생성해서 대입해야함
		Thread t1 = new Thread(new MyThread2(100, "첫번째..."));
		Thread t2 = new Thread(new MyThread2(200, "두번째..."));
		
		t1.start();
		t2.start();
		
		System.out.println("main 종료...");
		//main은 진작에 끝났고 스레드가 끝나야 프로그램이 종료된다.
		
		/* 실행결과
		main 시작...
		main 종료...
		두번째...:0
		첫번째...:0
		두번째...:1
		첫번째...:1  */
			
	}

}

Runnable 인터페이스를 활용한 스레드는 implements를 통해 인터페이스를 구현함.

여기서 sleep 메서드를 쓸 때는 앞에 Thread를 붙여줘야 한다. -> Thread.sleep(100);


Thread(스레드) 우선순위

 

Thread객체. setPriority(int newPRIORITY) 메서드를 이용

package com.day15;

//스레드 우선 순위 지정
//  => Thread객체.setPriority(int newPRIORITY)메소드를 이용
class MyThread4 extends Thread {
	
	private String name;
	
	public MyThread4(String name) {
		
		this.name = name;
	}
	
	@Override
	public void run() {
		
		for(int i=1; i<=20; i++) {
			System.out.println(name + ":" + i);
		}
	}
	
	
}

public class Test4 {
	
	public static void main(String[] args) {
		//Runnable을 받은 스레드 객체 생성 방법
		//Runnable은 인터페이스타입이기에 구현 객체를 생성해서 대입해야함
		MyThread4 ob1 = new MyThread4("A");
		MyThread4 ob2 = new MyThread4("B");
		MyThread4 ob3 = new MyThread4("C");
		
		// 우선순위 종류(1~10)
		System.out.println("Min: " + Thread.MIN_PRIORITY); // 1
		System.out.println("Nor: " + Thread.NORM_PRIORITY); // 5  - (기본) 스레드는 기본으로 5를 갖게된다
		System.out.println("Max: " + Thread.MAX_PRIORITY); // 10
		
		//기본 스레드의 우선순위
		System.out.println(ob1.getPriority()); // 5
		System.out.println(ob2.getPriority()); // 5
		System.out.println(ob3.getPriority()); // 5
		
		//우선순위 변경
		ob1.setPriority(Thread.MIN_PRIORITY); // 1
		//ob1.setPriority(1); ->위의 코딩 MIN대신 1 써도 된다. 아래 코딩도 가능
		ob2.setPriority(Thread.NORM_PRIORITY); // 5
		ob3.setPriority(Thread.MAX_PRIORITY); // 10
		
		ob1.start();
		ob2.start();
		ob3.start();
		//c b a순으로 실행됨
	}
}

스레드 우선순위는 1이 가장 낮고, 10이 가장 높다. 그리고 기본 스레드 우선순위는 5이다.

스레드 우선순위를 변경할 때는 setPriority를 사용하면 된다.

 


데몬 스레드

다른 스레드에 도움을 주는 스레드로 다른 스레드가 종료되면 데몬 스레드가 종료되지 않더라도 프로세스가 종료

package com.day15;
//데몬 스레드 : 다른 스레드에 도움을 주는 스레드로 다른 스레드가 종료되면 
//				데몬스레드가 종료되지 않더라도 프로세스가 종료된다.

class MyThread5 implements Runnable {

	@Override
	public void run() {
		
		for(int i=1; i<=20; i++) {
			System.out.println(i);
			//1부터 20까지 찍는 작업
			//스레드일때는 - sleep / 인터페이스(Runnable)일때는 Thread.sleep
			try {
				Thread.sleep(100);
			} catch (Exception e) {
				
			}
		}
		
	}
	
}
public class Test5 {

	public static void main(String[] args) {
		
		System.out.println("main 시작...");
		//Runnable을 받은 스레드 객체 생성 방법
		//Runnable은 인터페이스타입이기에 구현 객체를 생성해서 대입해야함
		Thread t1 = new Thread(new MyThread5());
		Thread t2 = new Thread(new MyThread5());
		Thread t3 = new Thread(new MyThread5());
		
		//데몬 스레드 : 다른 스레드에 도움을 주는 스레드로 다른 스레드가 종료되면 
		//				데몬스레드가 종료되지 않더라도 프로세스가 종료된다.
		
		t1.setDaemon(true);
		t2.setDaemon(true);
		t3.setDaemon(true);	//main이 종료되면 다른 스레드도 종료된다 - 이게 데몬 스레드
		
		////////////////////////////////////////////////////////////////
		t1.start();
		t2.start();
		t3.start();
		
		//main 잠깐 쉬게 하기
		try {
			Thread.sleep(1000); //main 1초 쉬기
		} catch (Exception e) {
			
		}
		//////////////////////////////////////////
		
		//위에 스레드가 끝날때 까지 기다리다가 main 종료
		try { //join이 있으면 sleep이 필요없다
			t1.join(); // t1이 끝날때까지 기다려
			t2.join();
			t3.join();
		} catch (Exception e) {
			// TODO: handle exception
		}
		////////////////////////////////////////////
		System.out.println("main 종료...");
	}

}

Thread(스레드) 동기화

 

- 다중 스레드 프로그램의 문제점

    => 스레드는 독립적으로 명령을 실행하는데 이때 각각의 스레드가 동시에 공유된 데이터에 접근할 
       경우 데이터 처리에 오작동이 발생할 수 있다.

  - 동기화 => 스레드가 공유된 데이터를 처리할 경우 먼저 접근한 스레드가 다른 스레드의 접근을
              차단하기 위해 Lock를 걸어주는 기능

  - 동기화 방법

    1) 공유된 데이타를 처리하는 메서드를 동기화시키는 방법

       형식) synchronized 반환형 메서드명(매개변수,...)
             {
                  공유 데이터를 처리하는 명령;
             }

    2) 공유된 데이터를 처리하는 메서드를 호출하는 영역을 동기화시키는 방법

       형식) synchronized(객체명)   => 공유된 데이터를 포함하고 있는 객체 
             {
                   객체명.메서드명(값,..);//공유된 데이터를 처리하는 메서드
             }

 

 

스레드 동기화

package com.day15;

// 스레드 동기화

class MyThread8 implements Runnable {
	
	private int bank = 10000; // 잔액
	
	//잔액을 보여주는 getBank()
	private int getBank() { 
		return bank;
	}
	
	//출금 drawMoney
	private int drawMoney(int m) {
		bank -= m; // bank = bank - m;
		return m; // 인출 금액
	}

	@Override
	public void run() {
		
		int moneyNeed = 6000; // 인출할 금액
		int money;
		String msg = "";
		
		try {
			
			// 동기화 블럭
			synchronized (this) {
				
			if(getBank() >= moneyNeed) {
				
				money = drawMoney(moneyNeed);
				msg = "인출 성공!!";
				
			} else {
				money = 0;
				msg = "인출 실패!!거지냐?";
				}
			}
			System.out.println(Thread.currentThread().getName() + msg + ", 인출금액:" + money + ",잔고:" + getBank());
			
			
		} catch (Exception e) {
			
		}
	}
}
public class Test8 {

	public static void main(String[] args) {
		
		MyThread8 ob = new MyThread8(); //객체 생성 - 여기서 시작
		
		
		//Thread t1 = new Thread(new MyThread5());
		//Thread t2 = new Thread(new MyThread5());  아래랑 다르다. 여긴 각자 만들어서 사용하고 아래는 ob를 공유
		Thread t1 = new Thread(ob);				
		Thread t2 = new Thread(ob);	// ex ) t1로 ob에서 3천원빼고 t2로 ob에서 4천원빼기
		
		t1.start();
		t2.start();
		

	}

}

 

벌써 자바가 끝나간다.. 참 시간이 빠르다. 왕복 3시간이 넘게 학원을 다니니 시간이 부족해서 운동을 못하고 공부 시간도 매우 부족하다. 그래서 주변에 고시원 or원룸을 찾아볼 예정이다. 난 이해하는 속도가 매우 느려서 절대적인 공부시간을 확보해야 한다. 
반응형

블로그의 정보

무작정 개발

무작정 개발

활동하기