본문 바로가기
Study/Java Study

자바스터디 9주차 (1)

by hongchii 2021. 7. 5.
728x90
반응형

2021.07.04 - [Study/Java Study] - 자바스터디 8주차 (2)

 

자바스터디 8주차 (2)

2021.06.28 - [Study/Java Study] - 자바스터디 8주차 (1) 자바스터디 8주차 (1) 2021.06.23 - [Study/Java Study] - 자바스터디 7주차 (2) 자바스터디 7주차 (2) 2021.06.22 - [Study/Java Study] - 자바스터디 7..

hong-chii.tistory.com

 

1.프로세스와 쓰레드

프로세스는 프로그램을 수행하는 데 필요한 데이터와 메모리 등의 자원 그리고 쓰레드로 구성되어 있으며, 프로세스의 자원을 이용해서 실제로 작업을 수행ㅇ하는 것이 바로 쓰레드이다.

모든 프로세스에는 최소한 하나 이상의 쓰레드가 존재하며, 둘 이상의 쓰레드를 가진 프로세스를 '멀티쓰레드 프로세스'라고 한다.

 

멀티쓰레딩은 하나의 프로세스 내에서 여러 쓰레드가 동시에 작업을 수행하는 것이다.

 

멀티쓰레딩의 장점

  • CPU의 사용률을 향상시킨다.
  • 자원을 보다 효율적으로 사용할 수 있다.
  • 사용자에 대한 응답성이 향상된다.
  • 작업이 분리되어 코드가 간결해진다.

 

 

2. 쓰레드의 구현과 실행

쓰레드를 구현하는 방법은 Thread클래스를 상속받는 방법과 Runnable인터페이스를 구현하는 방법이 있다.

// 1. Thread클래스를 상속
class MyThread extends Thread {
	public void run() { // Thread클래스의 run을 오버라이딩
    /* 작업 내용 */
}
// 2. Runnable인터페이스를 구현
class MyThread implements Runnable {
	public void run() { // Runnable인터페이스의 run()을 구현
    /* 작업내용 */
}

Thread클래스를 상속받으면 다른 클래스를 상속받을 수 없기 때문에, Runnable인터페이스를 구현하는 방법이 일반적이고, 재사용성이 높고, 코드의 일관성을 유지할 수 있기 때문에 보다 객체지향적인 방법이라고 할 수 있다.

 

package Ch13;

public class ThreadEx1 {

	public static void main(String[] args) {
		ThreadEx1_1 t1 = new ThreadEx1_1();

		Runnable r = new ThreadEx1_1();
		Thread t2 = new Thread(r); // 생성자 Thread(Runnable target)

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

class ThreadEx1_1 extends Thread {
	public void run() {
		for (int i = 0; i < 5; i++) {
			System.out.println(getName()); // 조상인 Thread의 getName()을 호출
		}
	}
}

class ThreadEx1_2 implements Runnable {
	public void run() {
		for (int i = 0; i < 5; i++) {
			// Thread.currentThread() - 현재 실행중인 Thread를 반환한다.
			System.out.println(Thread.currentThread().getName());
		}
	}
}

쓰레드의 실행 - start()

start()가 호출되면 실행대기 상태에 있다가 자신의 차례가 되면 실행된다.

한 번 실행이 종료된 쓰레드는 다시 실행할 수 없다. 하나의 쓰레드에 대해 start()는 한번만 호출될 수 있다.

 

 

 

3. start()와 run()

main메서드에서 run()을 호출하는 것은 생성된 쓰레드를 실행시키는 것이 아니라 단순히 클래스에 선언된 메서드를 호출하는 것일뿐이다.

 

새로운 쓰레드를 생성하고 start()를 호출한 후 호출스택의 변화

1. main메서드에서 쓰레드의 start()를 호출한다.
2. start()는 새로운 쓰레드를 생성하고, 쓰레드가 작업하는데 사용될 호출스택을 생성한다.
3. 새로 생성된 호출스택에 run()이 호출되어, 쓰레드가 독립된 공간에서 작업을 수행한다.
4. 이제는 호출스택이 2개이므로 스케줄러가 정한 순서에 의해서 번갈아 가면서 실행된다.

 

 

4. 싱글쓰레드와 멀티쓰레드

 

하나의 쓰레드로 사용자의 입력을 받는 작업과 화면에 숫자를 출력하는 작업을 처리하기 때문에 사용자가 입력을 마치기 전까지는 화면에 숫자가 출력되지 않다가 사용자가 입력을 마치고 나면 화면에 숫자가 출력된다.

package Ch13;

import javax.swing.JOptionPane;

public class ThreadEx6 {

	public static void main(String[] args) throws Exception {
		String input = JOptionPane.showInputDialog("아무 값이나 입력하세요.");
		System.out.println("입력하신 값은 " + input + "입니다.");

		for (int i = 10; i > 0; i--) {
			System.out.println(i);
			try {
				Thread.sleep(1000);
			} catch (Exception e) {

			}
		}
	}

}

 

 

두개의 쓰레드로 나누어 처리했기 때문에 사용자가 입력을 마치지 않았어도 화면에 숫자가 출력된다.

package Ch13;

import javax.swing.JOptionPane;

public class ThreadEx7 {

	public static void main(String[] args) throws Exception {
		ThreadEx7_1 th1 = new ThreadEx7_1();
		th1.start();

		String input = JOptionPane.showInputDialog("아무 값이나 입력하세요.");
		System.out.println("입력하신 값은 " + input + "입니다.");
	}

}

class ThreadEx7_1 extends Thread {
	public void run() {
		for (int i = 10; i > 0; i--) {
			System.out.println(i);
			try {
				sleep(1000);
			} catch (Exception e) {

			}
		}
	}
}

 

 

5. 쓰레드의 우선순위

쓰레드는 우선순위(priority)라는 속성(멤버변수)을 가지고 있는데, 이 우선순위의 값에 따라 쓰레드가 얻는 실행시간이 달라진다.

 

쓰레드의 우선순위 지정하기

void setPriority(int newPriority) // 쓰레드의 우선순위를 지정한 값으로 변경한다.
int getPriority() // 쓰레드의 우선순위를 반환한다.

public static final int MAX_PRIORITY = 10 // 최대우선순위
public static final int MIN_PRIORITY = 1 // 최소우선순위
public static final int NORM_PRIORITY = 5 // 보통우선순위

쓰레드가 가질 수 있는 우선순위의 범위는 1~10이며 숫자가 높을수록 우선순위가 높다.

쓰레드의 우선순위는 쓰레드를 생성한 쓰레드로부터 상속받는다. main메서드를 수행하는 쓰레드는 우선순위가 5이므로 main메서드내에서 생성하는 쓰레드의 우선순위는 자동적으로 5가 된다.

 

 

6. 쓰레드 그룹

 

쓰레드 그룹은 서로 관련된 쓰레드를 그룹으로 다루기 위한 것으로, 폴더를 생성해서 관련된 파일들을 함께 넣어서 관리하는 것처럼 쓰레드 그룹을 생성해서 쓰레드를 그룹으로 묶어서 관리할 수 있다.  또한 폴더 안에 폴더를 생성할 수 있듯이 쓰레드 그룹에 다른 쓰레드 그룹을 포함 시킬 수 있다.

package Ch13;

public class ThreadEx9 {

	public static void main(String[] args) throws Exception {
		ThreadGroup main = Thread.currentThread().getThreadGroup();
		ThreadGroup grp1 = new ThreadGroup("Group1");
		ThreadGroup grp2 = new ThreadGroup("Group2");

		ThreadGroup subGrp1 = new ThreadGroup(grp1, "SubGroup1");

		grp1.setMaxPriority(3);

		Runnable r = new Runnable() {
			public void run() {
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {

				}
			}
		};

		new Thread(grp1, r, "th1").start();
		new Thread(subGrp1, r, "th2").start();
		new Thread(grp2, r, "th3").start();

		System.out.println(">>List of ThreadGroup : " + main.getName() + ", Active ThreadGroup :"
				+ main.activeGroupCount() + ", Active Thread :" + main.activeCount());

		main.list();
	}

}

 

7. 데몬 쓰레드

데몬 쓰레드는 다른 일반 쓰레드의 작업을 돕는 보조적인 역할을 수행하는 쓰레드이다.

 

boolean isDaemon() 
//쓰레드가 데몬쓰레드인지 확인한다. 데몬쓰레드이면 true를 반환한다.

void setDaemon(boolean on) 
//쓰레드를 데몬 쓰레드로 또는 사용자 쓰레드로 변경한다. 매개변수 on의 값을 true로 지정하면 데몬 쓰레드가 된다.

 

package Ch13;

public class ThreadEx10 implements Runnable {
	static boolean autoSave = false;

	public static void main(String[] args) {
		Thread t = new Thread(new ThreadEx10());
		t.setDaemon(true);
		t.start();

		for (int i = 1; i <= 10; i++) {
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
			}
			System.out.println(i);
			if (i == 5)
				autoSave = true;
		}
		System.out.println("프로그램을 종료합니다.");
	}

	public void run() {
		while (true) {
			try {
				Thread.sleep(3 * 1000);
			} catch (InterruptedException e) {

			}
			if (autoSave) {
				autoSave();
			}
		}
	}

	public void autoSave() {
		System.out.println("작업파일이 자동저장되었습니다.");
	}
}

 

8.쓰레드의 실행제어

 

1.쓰레드를 생성하고 start()를 호출하면 바로 실행되는 것이 아니라 실행 대기열에 저장되어 자신의 차례가 될 때 까지 기다려야한다. 실행대기열은 큐와 같은 구조로 먼저 실행대기 열에 들어온 쓰레드가 먼저 실행
2.실행대기상태에 있다가 자신의 차례까 되면 실행 상태가 된다.
3.주어진 실행시간이 다되거나 yield()를 만나면 다시 실행대기상태가 되고 다음 차례의 쓰레드가 실행상태가 됨
4.실행중에 suspend(), sleep(), wait(), join(), I/O block에 의해 일시정지상태가 될 수 있다. I/O block은 입출력작업에서 발생하는 지연상태를 말한다. 사용자의 입력을 기다리는 경우를 예로 들 수 있는데, 이런 경우 일시정지 상태에 있다가 사용자가 입력을 마치면 다시 실행대기 상태가 된다.
5.지정된 일시정지시간이 다되거나 notify(), resume(), interrupt()가 호출되면 일시 정지상태를 벗어나 다시 실행대기열에 저장되어 자신의 차례를 기다리게 된다.
6.실행을 모두 마치거나 stop()이 호출되면 쓰레드는 소멸된다.
  • sleep() - 일정시간동안 쓰레드를 멈추게 한다.
  • interrupt()와 interrupted() - 쓰레드의 작업을 취소한다.
  • suspend(), resume(), stop()
  • yield() - 다른 쓰레드에게 양보한다.
  • join() - 다른 쓰레드의 작업을 기다린다.

 

9. 쓰레드의 동기화

한 쓰레드가 진행 중인 작업을 다른 쓰레드가 간섭하지 못하도록 막는 것을 '쓰레드의 동기화(synchronization)'라고 한다.

 

 

9.1 synchronized를 이용한 동기화

// 1. 메서드 전체를 임계 영역으로 지정
public synchronized void calcSum() {

}

// 2. 특정한 영역을 임계 영역으로 지정
synchronized(객체의 참조변수) {

}

 

9.2 wait()과 notify()

wait(), notify(), notifyAll()
- Object에 정의되어 있다.
- 동기화 블록(synchronized블록)내에서만 사용할 수 있다.
- 보다 효율적인 동기화를 가능하게 한다.

 

 

자바의 정석을 토대로 공부 후 정리한 내용입니다.

728x90
반응형

'Study > Java Study' 카테고리의 다른 글

자바스터디 11주차 (1) - 입출력IO  (0) 2021.07.25
자바스터디 10주차 (1)  (0) 2021.07.12
자바스터디 8주차 (2)  (0) 2021.07.04
자바스터디 8주차 (1)  (0) 2021.06.28
자바스터디 7주차 (2)  (0) 2021.06.23

댓글