// 쓰레드(thread)
- 프로세스 내에서 실제 작업을 수행. 모든 프로세스는 최소한 하나의 쓰레드를 가지고 있음.
~ 프로세스: 실행중인 프로그램. 자원과 쓰레드로 구성됨.
- main 쓰레드 : main 메서드의 코드를 수행하는 쓰레드
- 사용자 쓰레드 / 데몬 쓰레드
~ 실행중인 사용자 쓰레드가 하나도 없을 때 프로그램 종료.
// 멀티쓰레드
- 둘 이상의 쓰레드
- 장점
① 시스템 자원을 보다 효율적으로 사용할 수 있음.
② 사용자에 대한 응답성이 향상됨.
③ 작업이 분리되어 코드가 간결해짐.
- 단점
① 동기화에 주의해야 함.
② 교착상태가 발생하지 않도록 주의해야 함.
③ 각 쓰레드가 효율적으로 고르게 실행될 수 있게 해야 함.
// 쓰레드의 구현 및 실행
- 쓰레드를 생성한 후에 start()를 호출해야 쓰레드가 작업을 시작한다.
① Thread 클래스 상속
//구현
class MyThread extends Thread {
public void run() { // Thread 클래스의 run()을 오버라이딩
...
}
}
// 실행
MyThread t1 = new MyThread(); // 쓰레드 생성
t1.start(); // 쓰레드 실행
② Runnable 인터페이스 구현 (더 나음!)
- static Thread currenThread() : 현재 실행중인 쓰레드의 참조 반환
- String getName() : 쓰레드의 이름 반환
// 구현
class MyThread2 implements Runnable {
public void run() { // Runnable 인터페이스의 추상메서드 run() 구현
...
}
}
// 실행
Runnable r = new MyThread2();
Thread t2 = new THread(r)
// 한 줄로 줄이면: Thread t2 = new Thread(new MyThread2());
t2.start();
- 싱글 쓰레드
① Thread 클래스 상속
public class Ex01 {
public static void main(String[] args) {
ThreadEx1 t1 = new ThreadEx1();
t1.start();
}
} // end of Ex01 class
class ThreadEx1 extends Thread{
public void run() {
for(int i = 0; i < 5; i++) {
System.out.println(this.getName());
}
}
}// end of ThreadEx1 class
//extends Thread
class Task1 extends Thread {
@Override
public void run() { //SIGNATURE
System.out.print("\nTask1 Started");
for(int i= 101; i <= 199; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask1 Done");
}
}
public class ThreadBasicsRunner {
public static void main(String[] args) {
//Task1
System.out.print("\nTask1 Kicked Off");
Task1 task1 = new Task1();
task1.start(); //※task1.done() X
//Task2
System.out.print("\nTask2 Kicked Off");
for(int i= 201; i <= 299; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask2 Done");
//Task3
System.out.print("\nTask3 Kicked Off");
for(int i= 301; i <= 399; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask3 Done");
System.out.print("\nMain Done");
} //main
}
② Runnable 인터페이스 구현
public class Ex01 {
public static void main(String[] args) {
Runnable r = new ThreadEx2();
Thread t2 = new Thread(r);
t2.start();
}
} // end of Ex01 class
class ThreadEx2 implements Runnable{
public void run() {
for(int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName());
}
}
}// end of ThreadEx2 class
//extends Thread
class Task1 extends Thread {
@Override
public void run() { //SIGNATURE
System.out.print("\nTask1 Started");
for(int i= 101; i <= 199; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask1 Done");
}
}
class Task2 implements Runnable {
@Override
public void run() {
System.out.print("\nTask2 Started");
for(int i= 201; i <= 299; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask2 Done");
}
}
public class ThreadBasicsRunner {
public static void main(String[] args) {
//Task1
System.out.print("\nTask1 Kicked Off");
Task1 task1 = new Task1();
task1.start(); //※task1.done() X
//Task2
System.out.print("\nTask2 Kicked Off");
Task2 task2 = new Task2();
Thread task2Thread = new Thread(task2);
task2Thread.start();
//Task3
System.out.print("\nTask3 Kicked Off");
for(int i= 301; i <= 399; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask3 Done");
System.out.print("\nMain Done");
} //main
}
- 멀티쓰레드
public class Ex01 {
public static void main(String[] args) {
ThreadEx1 t1 = new ThreadEx1();
Runnable r = new ThreadEx2();
Thread t2 = new Thread(r);
t1.start();
t2.start();
}
} // end of Ex01 class
class ThreadEx1 extends Thread{
public void run() {
for(int i = 0; i < 5; i++) {
System.out.println(this.getName());
}
}
}// end of ThreadEx1 class
class ThreadEx2 implements Runnable{
public void run() {
for(int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName());
}
}
}// end of ThreadEx2 class2
- 싱글 쓰레드
public class Ex02 {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
for(int i = 0; i < 300; i++) {
System.out.printf("%s", new String("-"));
}
System.out.println("소요시간1 : " + (System.currentTimeMillis() - startTime));
for(int i = 0; i < 300; i++) {
System.out.printf("%s", new String("|"));
}
System.out.println("소요시간2 : " + (System.currentTimeMillis() - startTime));
}
}
- 멀티 쓰레드
public class Ex03 {
static long startTime = 0;
public static void main(String[] args) {
startTime = System.currentTimeMillis();
Thread t1 = new Thread(new MyThread1());
Thread t2 = new Thread(new MyThread2());
t1.start();
t2.start();
}
}
class MyThread1 implements Runnable {
public void run() {
for(int i = 0; i < 300; i++) {
System.out.printf("%s", new String("-"));
}
System.out.println("소요시간1 : " + (System.currentTimeMillis() - Ex03.startTime));
}
}
class MyThread2 implements Runnable {
public void run() {
for(int i = 0; i < 300; i++) {
System.out.printf("%s", new String("|"));
}
System.out.println("소요시간2 : " + (System.currentTimeMillis() - Ex03.startTime));
}
}
// 쓰레드의 I/O 블락킹
- 싱글 쓰레드의 경우, 사용자로부터 입력을 기다리는 동안 아무 일도 하지 않는다.
- 멀티 쓰레드의 경우, 사용자로부터 입력을 기다리는 동안 다른 쓰레드가 수행된다.
- 싱글 쓰레드
import javax.swing.JOptionPane;
public class Ex04 {
public static void main(String[] args) {
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) {}
} // end of for
} // end of main method
}// end of Ex04 class
- 멀티 쓰레드
import javax.swing.JOptionPane;
public class Ex05 {
public static void main(String[] args) {
Thread t1 = new Thread(new Thread05());
t1.start();
String input = JOptionPane.showInputDialog("아무 값이나 입력하세요.");
System.out.println("입력하신 값은 " + input + "입니다.");
}
}
class Thread05 implements Runnable {
public void run() {
for(int i = 10; i > 0; i--) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch(Exception e) {}
} // end of for()
} // end of run()
} // end of Thred05
// 우선 순위
- 작업의 중요도에 따라 쓰레드의 우선순위를 다르게 하여 특정 쓰레드가 더 많은 작업시간을 갖게 할 수 있다.
- void setPriority(int newPriority) : 쓰레드의 우선순위를 지정한 값으로 변경
- int getPriority() : 쓰레드의 우선순위 반환
- 최대우선순위 = 10
- 최소우선순위 = 1
- 보통우선순위 = 5
※ request의 의미이지, 의무가 아니다. 설정한 우선순위대로 실행될 수도 있고, 아닐 때도 있다.
public class Ex06 {
public static void main(String[] args) {
Thread t1 = new Thread(new Thread1());
Thread t2 = new Thread(new Thread2());
t2.setPriority(7);
System.out.println("Priority of t1(-) : " + t1.getPriority());
System.out.println("Priority of t2(|) : " + t2.getPriority());
t1.start();
t2.start();
}
}
class Thread1 implements Runnable {
public void run() {
for(int i = 0; i < 300; i++) {
System.out.print("-");
for(int x = 0; x < 10000000; x++) {} //시간 지연용
}
}
}
class Thread2 implements Runnable {
public void run() {
for(int i = 0; i < 300; i++) {
System.out.print("|");
for(int x = 0; x < 10000000; x++) {} //시간 지연용
}
}
}
//extends Thread
class Task1 extends Thread {
@Override
public void run() { //SIGNATURE
System.out.print("\nTask1 Started");
for(int i= 101; i <= 199; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask1 Done");
}
}
class Task2 implements Runnable {
@Override
public void run() {
System.out.print("\nTask2 Started");
for(int i= 201; i <= 299; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask2 Done");
}
}
public class ThreadBasicsRunner {
public static void main(String[] args) {
//Task1
System.out.print("\nTask1 Kicked Off");
Task1 task1 = new Task1();
task1.setPriority(1);
task1.start(); //※task1.done() X
//Task2
System.out.print("\nTask2 Kicked Off");
Task2 task2 = new Task2();
Thread task2Thread = new Thread(task2);
task2Thread.setPriority(10);
task2Thread.start();
//Task3
System.out.print("\nTask3 Kicked Off");
for(int i= 301; i <= 399; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask3 Done");
System.out.print("\nMain Done");
} //main
}
// 쓰레드 그룹
- 서로 관련된 쓰레드를 그룹으로 묶어서 다루기 위한 것.
- 모든 쓰레드는 반드시 하나의 쓰레드 그룹에 포함되어 있어야 함.
- 쓰레드 그룹을 지정하지 않고 생성한 쓰레드는 main 쓰레드 그룹에 속함.
- 자신을 생성한 쓰레드(부모 쓰레드)의 그룹과 우선순위를 상속받음.
- 쓰레드 자신이 속한 쓰레드 그룹을 반환
ThreadGroup getThreadgroup()
- 처리되지 않은 예외에 의해 쓰레드 그룹의 쓰레드가 종료되었을 때, JVM에 의해 이 메서드가 자동적으로 호출됨.
void uncaughtException(Thread t, Throwble e)
- 쓰레드 그룹에 포함된 활성상태에 있는 쓰레드/쓰레드 그룹의 수를 반환
int activeCount()
int activeGroupCount()
- 현재 실행중인 쓰레드가 쓰레드 그룹을 변경할 권한이 있는지 체크
void checkAccess()
- 쓰레드 그룹과 하위 쓰레드 그룹까지 모두 삭제 // 비어있어야 삭제 가능!
void destroy()
- 쓰레드 그룹의 최대우선순위 반환
int getMaxPriority()
- 쓰레드 그룹의 이름 반환
String getName()
- 쓰레드 그룹의 상위 쓰레드 그룹 반환
ThreadGroup getParent()
- 쓰레드 그룹에 속한 모든 쓰레드를 interrupt
void interrupt()
- 쓰레드 그룹에 속한 쓰레드와 하위 쓰레드 그룹에 대한 정보 출력
void list()
- 지정된 쓰레드 그룹의 상위 쓰레드 그룹인지 확인
boolean parentOf(ThreadGroup g)
- 쓰레드 그룹의 최대 우선순위를 설정
void setMaxPriority(int pri)
//데몬 쓰레드
- 일반 쓰레드의 작업을 돕는 보조적인 역할 수행.
- 일반 쓰레드가 모두 종료되면 자동적으로 종료.
- 가비지 컬렉터, 자동저장, 화면 자동갱신 등에 사용됨.
- 무한루프와 조건문을 이용해서 실행 후 대기하다가 특정 조건이 만족되면 작업을 수행하고 다시 대기하도록 작성.
public void run() {
while(true) {
try {
Thread.sleep(3 * 1000); //3초마다
} catch(InterruptedException e) {}
// autoSave의 값이 true 이면 autoSave() 호출
if(autoSave) {
autoSave();
}
}
}
- 쓰레드가 데몬 쓰레드 그룹인지 확인. 데몬 쓰레드이면 true 반환
boolean isDaemon()
- 쓰레드를 데몬 쓰레드 또는 사용자 쓰레드로 변경. 매개변수를 true로 지정하면 데몬 쓰레드가 됨.
void setDaemon(boolean on)
~ 반드시 start()를 호출하기 전에 실행되어야 함!! 안 그러면 IllegalThreadStateException 발생.
public class Ex07 implements Runnable {
static boolean autoSave = false;
public static void main(String[] args) {
Thread t = new Thread(new Ex07());
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; }
} // end of for()
System.out.println("프로그램을 종료합니다.");
}// end of main()
public void run() {
while(true) {
try {
Thread.sleep(3 * 1000);
} catch(InterruptedException e) {}
if(autoSave) { autoSave(); }
} // end of while()
} // end of run()
public void autoSave() {
System.out.println("작업 파일이 자동 저장되었습니다.");
} // end of autoSave()
}// end of class
// 쓰레드의 상태
① NEW : 쓰레드가 생성되고 아직 start()가 호출되지 않은 상태
② RUNNABLE : 실행 중. 또는 실행 가능한 상태
③ BLOCKED : 동기화 블럭에 의해 일시정지된 상태
④ WAITING : 쓰레드의 작업이 종료되지는 않았지만 실행 가능하지 않은 일시정지 상태.
~ TIMED_WAITING : 일시정지 시간이 지정된 경우
⑤ TERMINATED : 쓰레드의 작업이 종료된 상태
// 쓰레드의 실행제어
- sleep() : 지정된 시간 동안 쓰레드를 일시정지시킴. 지정한 시간이 지나면 자동적으로 다시 실행 대기상태가 됨.
~ 예외처리를 해야 한다.(InterruptedException이 발생하면 깨어남.)
~ 특정 쓰레드를 지정해서 멈추게 하는 것은 불가능.
static void sleep(long millis)
static void sleep(long millis, int nanos)
- interrupt() : 대기상태(WAITING)인 쓰레드를 실행 대기상태(RUNNABLE)로 만든다.
~ 적절히 사용하면 응답성과 효율성을 높일 수 있음!
void interrupt() //쓰레드의 interrupted상태를 false에서 true로 변경
boolean isInterrupted() // 쓰레드의 interrupted 상태를 반환
static boolean interrupted() // 현재 쓰레드의 interrupted 상태를 알려주고, false로 초기화
- suspend() : 쓰레드를 일시정지시킴.
- resume() : suspend()에 의해 일시정지 상태에 있는 쓰레드를 실행 대기상태로 만듦.(재개)
- stop() : 쓰레드를 즉시 종료시킴.
~ @deprecated : 교착상태에 빠지기 쉬움.
void suspend()
void resume()
void stop()
- join() : 지정된 시간 동안 특정 쓰레드가 작업하는 것을 기다림.
~ 예외처리를 해야 한다.(InterruptedException이 발생하면 작업 재개)
void join() // 작업이 모두 끝날 때까지
void join(long millis) // 천분의 일초 동안
void join(long millis, int nanos) // 천분의 일초 + 나노초 동안
- yield() : 남은 시간을 다음 쓰레드에게 양보하고 자신은 실행 대기상태가 됨.
~ 적절히 사용하면 응답성과 효율성을 높일 수 있음!
static void yield()
※ static 메서드는 자기 자신에게만 적용 가능
- sleep()
public class Ex08 {
public static void main(String[] args) {
Thread t1 = new Thread(new Thread01());
Thread t2 = new Thread(new Thread02());
t1.start();
t2.start();
delay(2*1000);
System.out.print("<<main 종료>>");
}
static void delay(long millis) {
try {
Thread.sleep(millis); // 호출한 쓰레드를 2초 동안 잠자게
} catch(InterruptedException e) {}
}
}
class Thread01 implements Runnable {
public void run() {
for(int i = 0; i < 300; i++) {
System.out.print("-");
}
System.out.print("<<t1 종료>>");
}
}
class Thread02 implements Runnable {
public void run() {
for(int i = 0; i < 300; i++) {
System.out.print("|");
}
System.out.print("<<t2 종료>>");
}
}
- interrupt()
import javax.swing.JOptionPane;
public class Ex09 {
public static void main(String[] args) {
Thread09_1 t1 = new Thread09_1();
t1.start();
String input = JOptionPane.showInputDialog("아무 값이나 입력하세요.");
System.out.println("입력하신 값은 " + input + "입니다.");
t1.interrupt();//true
System.out.println("isInterrupted() : " + t1.isInterrupted());
}
}
class Thread09_1 extends Thread {
public void run() {
int i = 10;
while(i!=0 && !isInterrupted()) {
System.out.println(i--);
for(long x = 0; x < 9900000000000000L; x++) {} // 시간 지연
}
System.out.println("카운트가 종료되었습니다.");
}
}
- join()
public class Ex10 {
static long startTime = 0;
public static void main(String[] args) {
Thread t1 = new Thread(new ThreadEx01());
Thread t2 = new Thread(new ThreadEx02());
t1.start();
t2.start();
startTime = System.currentTimeMillis();
try {
t1.join(); // main 쓰레드가 t1의 작업이 끝날 때까지 기다림.
t2.join(); // main 쓰레드가 t2의 작업이 끝날 때까지 기다림.
} catch(InterruptedException e) {}
System.out.println("소요시간 : " + (System.currentTimeMillis() - Ex10.startTime));
}
}
class ThreadEx01 implements Runnable {
public void run() {
for(int i = 0; i < 300; i++) {
System.out.print(new String("-"));
}
} // end of run()
}
class ThreadEx02 implements Runnable {
public void run() {
for(int i = 0; i < 300; i++) {
System.out.print(new String("|"));
}
} // end of run()
}
//extends Thread
class Task1 extends Thread {
@Override
public void run() { //SIGNATURE
System.out.print("\nTask1 Started");
for(int i= 101; i <= 199; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask1 Done");
}
}
class Task2 implements Runnable {
@Override
public void run() {
System.out.print("\nTask2 Started");
for(int i= 201; i <= 299; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask2 Done");
}
}
public class ThreadBasicsRunner {
public static void main(String[] args) throws InterruptedException {
//Task1
System.out.print("\nTask1 Kicked Off");
Task1 task1 = new Task1();
task1.setPriority(1);
task1.start(); //※task1.done() X
//Task2
System.out.print("\nTask2 Kicked Off");
Task2 task2 = new Task2();
Thread task2Thread = new Thread(task2);
task2Thread.setPriority(10);
task2Thread.start();
//wait for tas1 to complete
task1.join(); //task1 thread가 끝날 때까지 대기
task2Thread.join(); //task1 thread가 끝날 때까지 대기
//Task3
System.out.print("\nTask3 Kicked Off");
for(int i= 301; i <= 399; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask3 Done");
System.out.print("\nMain Done");
} //main
}
- yield()
public class Ex11 implements Runnable {
boolean suspended = false;
boolean stopped = false;
Thread t1;
Ex11(String name) {
t1 = new Thread(this, name);
}
public void run() {
while(!stopped) {
if(!suspended) {
/*
작업 수행
*/
try {
Thread.sleep(1000);
} catch(InterruptedException e) {}
} else {
Thread.yield();
} // end of if - else
}// end of while
}// end of run()
}
// 쓰레드의 동기화(synchronization)
- 한 쓰레드가 진행 중인 작업을 다른 쓰레드가 간섭하지 못하게 막는 것
- 동기화하려면 간섭 받지 않아야 하는 문장들을 임계 영역으로 설정
- 임계 영역은 락을 얻은 단 하나의 쓰레드만 출입 가능(객체 1 : 락 1)
- 임계 영역의 개수를 최소화 하는 것이 좋음.
- synchronized를 이용한 동기화
① 메서드 전체를 임계 영역으로 지정
public synchronized void calcSum() {
...
}
public synchronized void withdraw(int money) {
if(balance >= money) {
try {
Thread.sleep(1000);
} catch(Exception e) {}
balance -= money ;
}
}
② 특정한 영역을 임계 영역으로 지정(더 나음)
synchronized(객체의 참조변수) {
...
}
public void withdraw(int money) {
synchronized(this) {
if(balance >= money) {
try {
Thread.sleep(1000);
} catch(Exception e) {}
balance -= money ;
}
}
}
- wait(), notify() : 동기화의 효율을 높여줌. Object 클래스에 정의되어 있으며, 동기화 블록 내에서만 사용할 수 있음.
~ wait() : 객체의 lock을 풀고 쓰레드를 해당 객체의 waiting pool에 넣음.
~ notify() : waiting pool에서 대기 중인 쓰레드 중의 하나를 깨움.
~ notifyAll() : waiting pool에서 대기 중인 모든 쓰레드를 깨움.
- 특정한 영역을 임계 영역으로 지정
public class Ex12 {
public static void main(String[] args) {
Runnable r = new Thread12();
new Thread(r).start();
new Thread(r).start();
}
}
class Account2 {
private int balance = 1000; //private으로 해야 동기화가 의미 有
public int getBalance() {
return balance;
}
public synchronized void withdraw(int money) {
if(balance >= money) {
try { Thread.sleep(1000); } catch(InterruptedException e) {}
balance -= money;
}
}
}
class Thread12 implements Runnable {
Account2 acc = new Account2();
public void run() {
while(acc.getBalance() > 0) {
int money = (int)(Math.random() * 3 + 1) * 100;
acc.withdraw(money);
System.out.println("balance: " + acc.getBalance());
}
}
}
- wait(), notify()
import java.util.ArrayList;
class Customer implements Runnable {
private Table table;
private String food;
Customer(Table table, String food) {
this.table = table;
this.food = food;
}
public void run() {
while(true) {
try { Thread.sleep(100); } catch (InterruptedException e) {}
String name = Thread.currentThread().getName();
table.remove(food);
System.out.println(name + " ate a " + food);
}
} // end of run()
} // end of Customer class
class Cook implements Runnable {
private Table table;
Cook(Table table) { this.table = table; }
public void run() {
while(true) {
int idx = (int)(Math.random() * table.dishNum());
table.add(table.dishNames[idx]);
try { Thread.sleep(10); } catch(InterruptedException e) {}
}
} //end of run()
}// end of Cook class
class Table {
String[] dishNames = {"donut", "donut", "burger"};
final int MAX_FOOD = 6;
private ArrayList<String> dishes = new ArrayList<>();
public synchronized void add(String dish) {
while(dishes.size() >= MAX_FOOD) {
String name = Thread.currentThread().getName();
System.out.println(name + " is waiting.");
try {
wait();
Thread.sleep(500);
} catch(InterruptedException e) {}
} // end of while()
dishes.add(dish);
notify();
System.out.println("Dishes: " + dishes.toString());
}// end of add()
public void remove(String dishName) {
synchronized(this) {
String name = Thread.currentThread().getName();
while(dishes.size() == 0) {
System.out.println(name + " is waiting.");
try {
wait();
Thread.sleep(500);
} catch(InterruptedException e) {}
} //end of while()
while(true) {
for(int i = 0; i < dishes.size(); i++) {
if(dishName.equals(dishes.get(i))) {
dishes.remove(i);
notify();
return;
}
}
try {
System.out.println(name + "is waiting.");
wait();
Thread.sleep(500);
} catch(InterruptedException e) {}
} // end of while(true)
} // end of synchronized(this)
}// end of remove()
public int dishNum() { return dishNames.length; }
} // end of Table class
public class Ex13 {
public static void main(String[] args) throws InterruptedException {
Table table = new Table();
new Thread(new Cook(table), "COOK").start();
new Thread(new Customer(table, "donut"), "CUST1").start();
new Thread(new Customer(table, "burger"), "CUST2").start();
Thread.sleep(2000);
System.exit(0);
}
}
- extends Thread
//extends Thread
class Task1 extends Thread {
@Override
public void run() { //SIGNATURE
System.out.print("\nTask1 Started");
for(int i= 101; i <= 199; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask1 Done");
}
}
public class ThreadBasicsRunner {
public static void main(String[] args) {
//Task1
System.out.print("\nTask1 Kicked Off");
Task1 task1 = new Task1();
task1.start(); //※task1.done() X
//Task2
System.out.print("\nTask2 Kicked Off");
for(int i= 201; i <= 299; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask2 Done");
//Task3
System.out.print("\nTask3 Kicked Off");
for(int i= 301; i <= 399; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask3 Done");
System.out.print("\nMain Done");
} //main
}
- implents Runnable
//extends Thread
class Task1 extends Thread {
@Override
public void run() { //SIGNATURE
System.out.print("\nTask1 Started");
for(int i= 101; i <= 199; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask1 Done");
}
}
class Task2 implements Runnable {
@Override
public void run() {
System.out.print("\nTask2 Started");
for(int i= 201; i <= 299; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask2 Done");
}
}
public class ThreadBasicsRunner {
public static void main(String[] args) {
//Task1
System.out.print("\nTask1 Kicked Off");
Task1 task1 = new Task1();
task1.start(); //※task1.done() X
//Task2
System.out.print("\nTask2 Kicked Off");
Task2 task2 = new Task2();
Thread task2Thread = new Thread(task2);
task2Thread.start();
//Task3
System.out.print("\nTask3 Kicked Off");
for(int i= 301; i <= 399; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask3 Done");
System.out.print("\nMain Done");
} //main
}
// ExecutorService
- 한번에 하나만 실행
~ ExecutorService.executorService = Excutors.newSingleThreadExecutor(); > 한번에 하나의 스레드만 동작
executorService.execute(스레드) : 스레드를 실행함.
executorService.shutdown() : 프로그램을 멈춰줌. (그렇지 않으면 작업이 끝나도 계속 동작함)
- 동시에 여러 개 실행
~ ExecutorService executorService = Executors.newFixedThreadPool(동시에 실행될 수);
executorService.execute(스레드)
executorService.shutdown()
- 한번에 하나만 실행
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorServiceRunner {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Task1());
executorService.execute(new Thread(new Task2()));
//Task3
System.out.print("\nTask3 Kicked Off");
for(int i= 301; i <= 399; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask3 Done");
System.out.print("\nMain Done");
executorService.shutdown(); //프로그램을 멈춰줘야 함.
} //main
}
- 동시에 여러 개 실행
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Task extends Thread {
private int number;
public Task(int number) {
this.number = number;
}
@Override
public void run() { //SIGNATURE
System.out.print("\nTask" + number + " Started");
for(int i= number*100; i <= number*100 + 99; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask1 Done");
}
}
public class ExecutorServiceRunner {
public static void main(String[] args) {
// ExecutorService executorService = Executors.newSingleThreadExecutor();
ExecutorService executorService = Executors.newFixedThreadPool(5);
executorService.execute(new Task(1));
executorService.execute(new Task(2));
executorService.execute(new Task(3));
executorService.execute(new Task(4));
//Task3
System.out.print("\nTask3 Kicked Off");
for(int i= 301; i <= 399; i++) {
System.out.print(i + " ");
}
System.out.print("\nTask3 Done");
System.out.print("\nMain Done");
executorService.shutdown(); //프로그램을 멈춰줘야 함.
} //main
}
// Callable로 후처리 스레드에서 돌아오기
1. Future<자료형> 변수명 = executorService.submit(Callable 구현 클래스);
2. 변수명.get() : Callable 구현 클래스 코드 실행값 반환
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
class CallableTask implements Callable<String> {
private String name;
public CallableTask(String name) {
this.name = name;
}
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "Hello " + name;
}
}
public class CallableRunner {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(1);
Future<String> welcomeFuture =
executorService.submit(new CallableTask("나무의 하루"));
System.out.println("new CallableTask(\"나무의 하루\") executed");
String welcomeMessage = welcomeFuture.get();
System.out.println(welcomeMessage);
System.out.println("Main complete");
executorService.shutdown();
} //main
}
- executorService.invokeAll() : 여러 개의 스레드 작업이 모두 끝날 때까지 대기 후 실행
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class MultipleCallableRunner {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(3);
List<CallableTask> tasks= List.of(new CallableTask("나무의 하루")
, new CallableTask("Hanee")
, new CallableTask("아침햇살"));
List<Future<String>> results = executorService.invokeAll(tasks);
for(Future<String> result:results) {
System.out.println(result.get());
}
executorService.shutdown();
} //main
}
- executorService.invokeAny() : 가장 빠르게 완료된 스레들의 결과 하나만 반환
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MultipleAnyCallableRunner {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newFixedThreadPool(3);
List<CallableTask> tasks= List.of(new CallableTask("나무의 하루")
, new CallableTask("Hanee")
, new CallableTask("아침햇살"));
String result = executorService.invokeAny(tasks);
System.out.println(result);
executorService.shutdown();
} //main
}
'자바(JAVA)' 카테고리의 다른 글
[자바(Java)] 스트림(stream) (0) | 2022.12.20 |
---|---|
[자바(Java)] 람다식 (0) | 2022.12.20 |
[자바(Java)] 애너테이션 (0) | 2022.12.17 |
[자바(Java)] 열거형(enum) (0) | 2022.12.17 |
[자바(Java)] 제네릭(Generics) (1) | 2022.12.17 |