20. JAVA 쓰레드 (Thread)

2020. 6. 8. 16:31·개발/JAVA
728x90
반응형

* 쓰레드 & 프로세스

- 프로세스란 '실행중인 프로그램'이며 쓰레드는 프로세스를 구성하는 '제어의 흐름'이다

- 모든 프로세스에는 최소한 하나 이상의 쓰레드가 존재한다

 

* 쓰레드 (Thread) 의 장점

- 프로세스의 공통 Resource를 공유하므로 '경량 프로세스'로 불린다

 

* 쓰레드 (Thread) 와 프로세스 (Process) 의 차이

- Process : 프로그램의 '실행단위'

- Thread : Process를 구성하는 '작업단위'

 

* 자바는 멀티쓰레드가 가능하다

- 하나의 프로세스 안에서 여러개의 쓰레드가 동시 작업하는 멀티 쓰레드

- main메소드(프로그램 진입점)을 가진 자바 프로그램은 하나의 스레드를 가진(main쓰레드) 단일 쓰레드이고

- Thread 클래스나 runnable 인터페이스를 상속받아 다른 쓰레드를 동작 시킬 수 있다

ex) for문 안에 for문 (2중 포문), while문 안에 while문 등등 멀티쓰레드가 가능

 

* 쓰레드 (Thread) 생성 방법 (실행 방법 Thread객체.start())

- java.lang.Thread 클래스 상속

ㄴ 쓰레드를 상속받는 클래스를 작성

ㄴ run() 메소드를 오버라이딩하여 내용부를 구현한다

ㄴ main() 메소드 내부에서 쓰레드를 상속받은 클래스의 객체를 생성

ㄴ 해당 객체의 start() 메소드를 호출한다

class D extends Thread{
	D() {
		start();
		int i = 0;
		while(true) {
			System.out.println("i: " + i++);
			try {
			Thread.sleep(1000);
			} catch(Exception e) {}
		}
	}
	public void run() {
		int j = 0;
		while(true) {
			System.out.println("j: " + j++);
			try {
			Thread.sleep(1000);
			} catch(Exception e) {}
		}
	}
	public static void main(String[] args) {
		new D();
	}
}

 

- java.lang.Runnable 인터페이스 상속

ㄴ Runnable을 구현하는 클래스 작성

ㄴ run() 메소드를 오버라이딩하여 내용부를 구현한다

ㄴ main() 메소드에서 Runnable을 구현한 클래스의 객체를 생성한다

ㄴ Thread 객체를 생성하여 매개변수로 위의 객체를 대입한다

ㄴ Thread 객체의 start()메소드를 호출한다

class E implements Runnable{
	E() {
		new Thread(this).start();

		int i = 0;
		while(true) {
			System.out.println("ii: " + i++);
			try {
			Thread.sleep(1000);
			} catch(Exception e) {}
		}
	}

	public void run() {
		int j = 0;
		while(true) {
			System.out.println("jj: " + j++);
			try {
			Thread.sleep(1000);
			} catch(Exception e) {}
		}
	}
	public static void main(String[] args) {
		new E();
	}
}

 

* 쓰레드 (Thread) 의 주요 메소드

- start() : 스레드가 수행을 시작하도록 한다.이때 자바가상머신은 이 스레드의 run()메서드를 호출한다

- static int activeCount() : 현재 활성화된 스레드의 수를 리턴한다

- static Thread currentThread() : 현재 실행중인 스레드를 리턴한다

- setName(String name) : 스레드의 이름을 주어진 이름으로 설정한다

- String getName() : 스레드의 이름을 리턴한다

- sleep(long millis) : 현재 실행중인 스레드를 밀리초동안 sleep시킨다

- static yield() : 현재 실행중인 스레드가 점유한 CPU를 내놓도록한다

즉,자기와 우선순위가 같거나 높은 스레드에게 실행기회를 준다.

- setPriority(int priorty) : 스레드의 우선순위를 설정한다

- int getPriority() : 스레드의 우선 순위를 반환 한다

- join() : 스레드가 종료 될때 까지 기다린다. 데몬 스레드의 강제 종료를 막기 위해 join()메서드를 호출하면

메인 스레드가 종료되어도 데몬 스레드가 완료되어야 종료 된다

- wait() : 현재 스레드를 대기 상태로 만든다.

- notify() : wait()로 대기 상태가 된 스레드를 다시 runnable상태로 만든다.

 

* 쓰레드 (Thread) 의 주요 상수

- 스레드에 할당 할 수 있는 우선권의 종류

ㄴ static final int MAX_PRIORITY :최대 우선권

ㄴ static final int MIN_PRIORITY : 최소 우선권

ㄴ static final int NORM_PRIORITY: 보통 우선권

* setPriority() 메서드로 우선권을 설정하고 getPriority() 메서드로 현재 스레드의 우선권을 얻어 온다

class Th1 extends Thread {
	public void run() {
		for(int i=0; i<10000; i++) {
			System.out.println("Th1 i: " + i);
		}
	}
}

class Th2 extends Thread {
	public void run() {
		for(int i=0; i<10000; i++) {
			System.out.println("Th2 i: " + i);
		}
	}
}

class G extends Thread{
	G() {/*
		int max = Thread.MAX_PRIORITY;
		int min = Thread.MIN_PRIORITY;
		int norm = Thread.NORM_PRIORITY;
		System.out.print(max + "\n" + min + "\n" + norm);*/
	}

	void init() {
		Th1 th1 = new Th1();
		th1.setPriority(Thread.MAX_PRIORITY);
		Th2 th2 = new Th2();
		th2.setPriority(Thread.MIN_PRIORITY);
		th2.yield();
		th1.start();
		th2.start();
		/*
		setPriority(Thread.MIN_PRIORITY);
		//int pri = getPriority();
		//System.out.println("getPriority(): " + pri);
		start();	// JVM -> (새)스레드
		selfM();	// main() 스레드*/
	}

	public static void main(String[] args) {
		new G().init();
	}
}

 

* 동기화 (Synchronized)

- 공유 메모리를 여러 스레드가 동시에 사용하지 못하도록 하는 것 (lock을 건다)

즉, 하나의 스레드만이 공유 메모리를 참조 할 수 있도록 제한 하는 방법

 

- synchronized 는 메소드에 사용이 가능한 modifier로서, 여러 스레드에 의해 특정 객체의 메소드들이

동시 호출되는 것에 대해 잠금(lock)을 설정하여,거부하도록 하는 기능을 지원한다.

즉, 코드의 한부분 또는 동기화된 메소드가 다른 스레드와 동시에 수행될 수 없게 하는 것

class H extends Thread{
	H() {
		m1();		// 메인 스레드
		m2();
		start();	// 새 스레드
	}

	public void run() {
		m1();
		m2();
	}

	synchronized void m1() {
		System.out.println("m1()");
	}

	void m2() {
		System.out.println("1");
		{synchronized(this) {
			System.out.println("2");
		}}
		System.out.println("3");
	}

	public static void main(String[] args) {
		new H();
	}
}

 

* 쓰레드 강제 정지 (Thread객체.interrupt())

- 쓰레드가 진행중에 강제로 정지하고자 할때 사용한다

- 플래그 방식과 interrupt()메소드 호출, 이 두가지가 있지만 웬만하면 interrupt() 사용 권장


* 데몬 쓰레드 (Daemon)

- 독립쓰레드(Non Daemon 쓰레드) - 메인쓰레드와 working쓰레드(개발자가 만든 쓰레드)

- 메인쓰레드가 끝나도 종료되지 않고 쓰레드가 Dead상태 될때 까지 계속 실행되는 메소드

 

- 종속쓰레드(Daemon 쓰레드) - 모든 독립쓰레드가 끝나면 자동으로 종료(Dead)가 되는 쓰레드

- 주쓰레드의 보조역할을 하는 쓰레드

- 종속 쓰레드는 주로 무한루프로 구성한다

ex) 배경음악 깐다든지, 10분마다 자동저장한다든지 등등

* 어떤 쓰레드를 종속쓰레드로 만들려면 setDaemon(true)로 설정

// 종속 쓰레드로 사용할 쓰레드]
// 1] Thread 클래스 상속
class DaemonThread extends Thread{
	// 2] run메소드 오버라이딩
	@Override
	public void run() {
		while(true) {
			System.out.println(String.format("%s] 배경음악이 흘러요", getName()));
			try {
				sleep(3000);
				System.out.println(String.format("%s] 3초마다 저장", getStackTrace()));
			} catch(InterruptedException e) {
				e.printStackTrace();
			}// try~catch
		}// while
	}// run()
}// class DaemonThread

public class ThreadApp {
	public static void main(String[] args) throws InterruptedException {
		System.out.println("[main 쓰레드 시작]");
//		쓰레드로 구현하지 않은 클래스 테스트]
//		NotThread nt1 = new NotThread("1st 클래스");
//		nt1.notThreadMethod();
//		NotThread nt2 = new NotThread("2st 클래스");
//		nt2.notThreadMethod();
//		쓰레드로 구현한 클래스 테스트]
		YesThread yt1 = new YesThread("1st 쓰레드");
//		메소드로 쓰레드명 설정
		yt1.setName("첫번째 쓰레드");// 위 1st 에서 첫번째로 바뀜
		yt1.start();// 쓰레드를 Running상태로 전이시킴
//		join() 메소드]
//		1] start()호출 후에 join()메소드를 호출해야 한다
//		2] join()메소드를 호출한 쓰레드가 실행이 끝나야 다음 쓰레드가 동작한다
//		yt1.join();
		YesThread yt2 = new YesThread("2st 쓰레드");
//		쓰레드의 우선권 설정]
//		우선순위가 높다고 그 쓰레드가 먼저 실행된다는 보장은 없다(확률만 높을뿐)
		yt2.setPriority(Thread.MAX_PRIORITY);
		yt2.start();
		
//		쓰레드명 미 설정시 자동으로 부여됨]
		DaemonThread daemon = new DaemonThread();
		daemon.setName("데몬쓰레드");
		daemon.setDaemon(true);// 종속쓰레드 설정
		daemon.start();// 쓰레드 Runnable 상태로 만든다
		System.out.println("현재 활성화 상태(Runnable or Running상태) 있는 쓰레드 수: " + Thread.activeCount());
		System.out.println("첫번째 쓰레드의 우선권: " + yt1.getPriority());
		System.out.println("두번째 쓰레드의 우선권: " + yt2.getPriority());
		System.out.println("현재 실행중인(Running) 쓰레드 명: " + Thread.currentThread().getName());
		System.out.println("main 쓰레드의 우선권: " + Thread.currentThread().getPriority());
		System.out.println("[main 쓰레드 끝]");
	}// main
}// class

 


예제)

- Runnable

class Command {
	void longedMethod() {
		for (int i = 0; i <= 10; i++) {
			System.out.println(
                               String.format("[실행중인 쓰레드명] - %s , i = %d", 
                               Thread.currentThread().getName(), i));
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			} // try~catch
		} // for
	}// longedMethod()
}// class Command

// 1] Runnable 인터페이스 상속
class Soldier extends Command implements Runnable {
// 2] run() 오버라이딩
	@Override
	public void run() {
		longedMethod();
	}// run()
}// class Soldier

public class RunnableApp {
	public static void main(String[] args) {
//		1] Runnable 타입을 Thread클래스의 인자 생성자를 이용해서 Thread 타입으로 변환
		Soldier soldier = new Soldier();
		System.out.println(soldier instanceof Soldier);
		System.out.println(soldier instanceof Command);
		System.out.println(soldier instanceof Runnable);
//		System.out.println(soldier instanceof Thread);[x]
		Thread thread1 = new Thread(soldier);
		thread1.setName("첫번째 쓰레드");
		thread1.start();
		
		Thread thread2 = new Thread(soldier,"두번째 쓰레드");
		thread2.start();
	}// main
}// class

 

- synchronized

// 동기화 블락을 이용한 데이타 동기화
// 동기화 블락]
// synchronized(동기화할 객체){
// 동기화 할 로직
// }

class DataSyncClass {
//	여러쓰레드가 공유하는 메모리
	int shareData;

//	인자생성자
	public DataSyncClass(int shareData) {
		this.shareData = shareData;
	}// DataSyncClass(int shareData)

}// class DataSyncClass

// 공유 데이터를 사용하는 쓰레드
class DataSyncThread extends Thread {
//	[멤버변수]
//	공유할 데이터를 갖고있는 DataSyncClass 타입의 멤버
	DataSyncClass dsc;

//	일정하게 증가시킬 숫자를 저장할 멤버
	int inc;

//	쓰레드명을 저장할 멤버
	String threadName;

//	[인자생성자]
	public DataSyncThread(DataSyncClass dsc, int inc, String threadName) {
		super(threadName);
		this.dsc = dsc;
		this.inc = inc;
		this.threadName = threadName;
	}// DataSyncThread(DataSyncClass dsc, int inc, String threadName)

//	[오래걸리는 메소드]
//	DataSyncClass의 shareData에 저장된 값을 반복하면서 inc(증가분)만큼 누적해서 계속 저장
	void increase() {
		for (int i = 1; i <= 10; i++) {
			dsc.shareData += inc;
			System.out.println(
                    String.format("[쓰레드명: %s, 공유데이터:%d]", getName(), dsc.shareData));

			try {
				sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			} // try~catch
		} // for
	}// increase()

	@Override
	public void run() {
//		동기화 전]
//		increase();
		
//		동기화 후]
		synchronized (dsc) {
			increase();
		}
	}// run()
}// class DataSyncThread extends Thread

public class DataSynchronized {
	public static void main(String[] args) throws InterruptedException {
//		공유메모리를 갖고있는 클래스, 하나만 인스턴스화]
		DataSyncClass dsc = new DataSyncClass(10);
		
//		두개의 쓰레드 생성]
		DataSyncThread dst1 = new DataSyncThread(dsc, 2, "첫번째 쓰레드");
		dst1.start();
//		dst1.join(); // 데이터 동기화 없이 특정 쓰레드를 지정해서 동기화 작업을 하고자 할때
		DataSyncThread dst2 = new DataSyncThread(dsc, 5, "두번째 쓰레드");
		dst2.start();
	}// main
}// class

 

 

728x90
반응형
저작자표시 (새창열림)

'개발 > JAVA' 카테고리의 다른 글

22. JAVA Network 네트워크  (0) 2020.06.08
21. JAVA IO (Input / Output) / 파일 입출력 스트림 / 파일 (File) 클래스  (0) 2020.06.08
19. JAVA 예외(Exception) / try~catch~finally  (0) 2020.06.08
18. JAVA 클래스간 형변환 / 업캐스팅 / 다운캐스팅 / 내부클래스 (InnerClass)  (0) 2020.06.08
17. JAVA 인터페이스 (Interface) / 컬렉션 (Collection)  (0) 2020.06.08
'개발/JAVA' 카테고리의 다른 글
  • 22. JAVA Network 네트워크
  • 21. JAVA IO (Input / Output) / 파일 입출력 스트림 / 파일 (File) 클래스
  • 19. JAVA 예외(Exception) / try~catch~finally
  • 18. JAVA 클래스간 형변환 / 업캐스팅 / 다운캐스팅 / 내부클래스 (InnerClass)
joolog
joolog
  • joolog
    JOO
    joolog
  • 전체
    오늘
    어제
    • 분류 전체보기 (165)
      • 개발 (83)
        • JAVA (29)
        • PYTHON (9)
        • AWS (15)
        • DOCKER (2)
        • PERCONA (2)
        • ORACLE (14)
        • MYSQL (1)
        • 알고리즘 (0)
        • 기타 (11)
      • 툴 (5)
        • MARKDOWN (1)
        • GIT (1)
        • DOCKER (1)
        • PyCharm (2)
        • IntelliJ (0)
      • 일상 (35)
        • 맛집 (6)
        • 카페 (2)
        • 요리 (4)
        • 글씨 연습 (2)
        • 그저 일상 (7)
        • 내돈 내산 (11)
        • 홍보 (1)
      • 국내 여행 (1)
      • 해외 여행 (15)
        • 체코-오스트리아 (10)
        • 일본 (5)
      • 암 일지 (26)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 글쓰기
    • 관리
    • 티스토리 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    자바
    mysql
    자바JDBC
    저요오드식
    재발
    오블완
    성모샘쉼터
    요양병원
    오스트리아
    오라클
    jdbc
    Oracle
    글씨연습
    오닉스 리프3
    티스토리챌린지
    히로시마
    체코
    잘츠부르크
    동위원소
    갑상선 암
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
joolog
20. JAVA 쓰레드 (Thread)
상단으로

티스토리툴바