쓰레드 Thread
쓰레드는 독립적인 실행단위이다. 우리가 한글문서를 작성하면서 프린트로 인쇄하거나 인터넷을 하며 음악을 듣는것 처럼 한번에 두 가지 이상의 프로세스를 실행가능하게 해 준다. 하지만 실제로 동시에 두 개가 실행되지는 않고 프로세스를 쪼개서 각각 Time Slot에 넣고 번갈아 실행하므로 실은 동시에 돌아가는것처럼 보일뿐이다.
package java11;
//싱글 스레드
class ThreadEx extends Thread { //내장클래스 상속
@Override
public void run() {
for (int i=0; i<=10; i++) {
System.out.println("Thread activated");
}
}
}
public class Test07 {
public static void main(String[] args) {
ThreadEx t = new ThreadEx();
t.run(); // t.start()를 사용해서 병렬스레드를 실행시킬 수 있다. start는 내장
System.out.println("End of main method");
}
}
package java11;
class Thread_mul1 extends Thread {
@Override
public void run() {
for (int i=0; i<=30; i++) {
System.out.print("100");
}
}
}
class Thread_mul2 extends Thread {
@Override
public void run() {
for (int i=0; i<=30; i++) {
System.out.print("200");
}
}
}
public class Test08 {
public static void main(String[] args) {
Thread_mul1 mt1 = new Thread_mul1();
Thread_mul2 mt2 = new Thread_mul2();
mt1.start();
mt2.start();
}
}
package java11;
class Thread_mul1 extends Thread {
@Override
public void run() {
for (int i=0; i<=30; i++) {
System.out.print("1");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Thread_mul2 extends Thread {
@Override
public void run() {
for (int i=0; i<=30; i++) {
System.out.print("2");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Test08 {
public static void main(String[] args) {
Thread_mul1 mt1 = new Thread_mul1();
Thread_mul2 mt2 = new Thread_mul2();
mt1.start();
mt2.start();
}
}
package java11;
class Thread_Ex extends Thread {
private int[] temp;
public Thread_Ex() {
temp = new int[10]; //Thread_Ex temp = new Thread_Ex();
for (int i=0; i<temp.length; i++) {
temp[i] = i;
}
}
public void run() {
for (int i : temp) { // 확장 for문 : temp에 데이터가 있는동안
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("temp : " +temp[i]);
}
}
}
public class Test09 {
public static void main(String[] args) {
Thread_Ex te1 = new Thread_Ex();
te1.start(); //run()을 찾아가서 실행
try {
Thread.sleep(2000);
System.out.println("프로그램 종료");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Thread클래스 (java.lang.Thread)에는 많은 메서드가 있는데 그 중 단일 쓰레드는 run()을 사용하고, 멀티 쓰레드 start()를 오버라이드해서 사용할 수 있는데, start()를 사용하면 내부적으로 run()도 실행된다. 멀티 쓰레드를 처리할 때에는 시차를 주기 위해서 Object.sleep(sec); 을 주어서 두 쓰레드 사이에 격차를 주고 실행시키기도 한다.
=> Thread와 동일한 개념으로 사용될 수 있는 것으로 Runnable 인터페이스가 있다.
class Thread_Ex extends Thread { .. } 를
class Runnable_Ex Implements Runnable { ...} 식으로 사용한다.
Runnable 인터페이스에서는 단일쓰레드만 빠르게 취급하므로 run() 하나만 사용하면 된다. start()를 쓴다면 객체를 생성해야한다.
재사용성이 높고(일단 Thread 클래스는 한번 상속받으면 타 클래스를 상속받기 어렵기 때문에 다수의 상속이 가능한 인터페이스가 좋을 수 있다.) 코드의 일관성을 유지할 수 있어서 일부 수행에 있어서는 Thread보다 더 효율적일 수 있다. start()를 사용하면 실행에 필요한 스택stack(메모리)를 확보한 뒤 run()을 각각 호출해서 사용하기 떄문에 멀티 쓰레드가 가능한 것이다.
package java11;
class Thread_ex2 implements Runnable { //class Thread_ex2 extends Thread
int temp[];
public Thread_ex2() {
temp = new int[10];
for (int i=0; i<temp.length; i++) {
temp[i] = i;
}
}
public void run() {
for (int i=0; i<temp.length; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("temp : " + temp[i]);
}
}
}
public class Test10 {
public static void main(String[] args) {
Thread_ex2 te1 = new Thread_ex2();
Thread te2 = new Thread(te1); //내장클래스
te2.start();
}
}
package java11;
public class Test12 implements Runnable {
public static void main(String[] args) {
System.out.println("메인클래스 start");
Test12 tt1 = new Test12();
Thread tt2 = new Thread(tt1); //Thread의 객체를 넣고 새 Thread객체 생성
tt2.start(); //run을 호출
System.out.println("해피엔딩");
}
public void run() {
System.out.println("run()");
first();
}
public void first() {
System.out.println("first()");
second();
}
public void second() {
System.out.println("second()");
}
}

결과를 보면 ‘메인 클래스 시작’ > run() > first() > second() > ‘메인 클래스 종료’ 순서 대로 나와야 할 것 같지만 실제로는 그렇지 않다. ‘메인 클래스 시작’ 한 뒤 start()를 호출하기 때문에 run()로 실행되고, first(), second(), 다시 메인 클래스로 와서 ‘메인 클래스 끝’을 보여야 하지만 ‘메인 클래스 시작’ > ‘메인 클래스 종료’ > run() > first() > second() 이렇게 출력이 된다. 메인 클래스가 실행된 이후에 스레드 객체를 호출하고 start()를 사용해 run()을 호출했지만 run()이 호출되기 전에 그 아래 줄인 '메인클래스 종료'가 먼저 출력되었기 때문이다.
===>이처럼 스레드를 사용하면 '위에서 아래로, 좌에서 우'로 라고 하는 작업순서를 따르게 되지 않을 수도 있다.
package java12;
import java.util.Scanner;
public class Q1 implements Runnable {
private int num;
public Q1(int n) {
this.num =n;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.print("1이상의 숫자를 입력해주세요 : ");
Q1 q1 = new Q1(scan.nextInt());
Thread th = new Thread(q1);
// Runnable th = new Q1();
th.start();
}
@Override
public void run() {
for (int i=num; i>=0; i--) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
System.out.println(i);
}
System.out.println("종료");
}
}
Daemon Thread
다른 일반 쓰레드의 작업을 보조하는 역할을 수행한다. 함께 구동중인 일반스레드가 종료되면 데몬스레드도 함꼐 종료된다. 예를들어 묹서를 작성하는 도중 3초간격으로 자동 세이브가 필요한 경우 사용할 수 있다.
package java12;
public class Test01 implements Runnable {
static boolean autoSave = false; //추상메서드 필요
public static void main(String[] args) {
Test01 dm = new Test01();
Thread th = new Thread(dm);
th.setDaemon(true); //추상메서드
th.start(); //추상메서드
for (int i = 1; i<= 15; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print("*");
if (i==3) {
autoSave=true;
}
}
System.out.println("프로그램 종료");
}
public void run() {
while (true) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (autoSave == true) {
System.out.println("Auto saving...");
}
}
}
}

쓰레드의 Join
하나의 쓰레드가 끝난뒤 다시 이어서 작업하는것이 Join(메서드)이다.
package java12;
public class Test02 implements Runnable {
public static void main(String[] args) {
System.out.println("메인 클래스 시작");
Test02 tj = new Test02();
Thread th = new Thread(tj);
// Runnable th = new Test02();
th.start(); //추상메서드
try {
th.join(); //추상메서드, 모든 메서드가 끝날때까지 대기
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("메인 클래스 종료");
}
@Override
public void run() {
System.out.println("run()");
first();
}
public void first() {
System.out.println("first()");
second();
}
public void second() {
System.out.println("second()");
}
}
'코딩 > JAVA' 카테고리의 다른 글
JAVA 29. 컬렉션 프레임워크 (0) | 2022.08.08 |
---|---|
JAVA 28-1. 쓰레드2 (0) | 2022.08.08 |
JAVA 27. 예외 (0) | 2022.08.08 |
JAVA 26. 내부 클래스 (0) | 2022.07.31 |
JAVA 25. ENUM (0) | 2022.07.31 |