: 독립적인 실행 흐름
: 실행 중인 하나의 program(Excel, Powerpoint, browser, game)
이런 program이 실행되려면 OS
로 부터 Resource
(자원)를 할당받아서 실행
OS(Operating System) : 운영체제 / windows, ubountu, MacOS
Resource(자원)
- code : 실행 명령어 코드
data : 전역, 정적 변수(global, variable, static variable)
Heap : 동적 할당 메모리 영역
Stack : method, 함수를 호출했을 때 local variable(지역변수)를 위한 영역
=> Resource 4가지를 이용해서 실제로 작업을 수행하는 것을 Thread
Single-Thread process
: 지금까지 작성한 Java program들 )Multi-Thread Process
)Java는 이런 Multi-Thread program 구현을 프로그램 언어차원에서 지원함
- process 내에 thread의
갯수 제한은 없음
=> Thread마다 독립적인 Stack이 할당
windows(OS)는 당연히 여러개의 process가 동시에 존재할 수 있다.
실제로 computer에서 일을 하는 주체는? CPU
(single core)
: core가 1개면 당연히 Multi processing(다중 처리)을 할 수 없음
=> 그러면 여러개의 프로그램을 동시에 실행할 수 있나요?
: Multi Tasking
: Time-slicing기법(시분할)을 이용해서 마치 동시에 진행되는 것처럼 동작시키는 기법
코어가 4개니까 동시에 작업할 수 있는 것도 4개
: CPU와 Resource를 효율적
으로 사용 가능
다중코어와 여러가지 메모리,코드 등을 공유해서 사용하기 때문에 효율이 좋음
: 사용자와의 응답성
을 높일 수 있음
: 적은 메모리로 더 빠르게
: 자원공유에 의한 동기화(Synchronization)
문제를 해결하기 위해 잘못하면 교착상태(dead-lock)
에 빠짐
* 교착상태
해결방안 : 교착상태 예방/회피/탐지/복구
방법
1. class MyClass extends Thread
: 이렇게 내가 정의한 Thread를 만들 수 있음
① 다중상속이 안 되기 때문에 제한이 생김
② 클래스의 결합도가 높아짐
2. interface를 이용하는 방법
: 조금 더 객체지향적 방법
<JavaThread 프로젝트 생성>
ThreadEx_01.java
예제1)
package sampleproj;
class ThreadEx_01_01 extends Thread {
// 새로운 독립적인 실행 흐름
// 프로그램의 entry point에 준하는 무언가 시작 method가 있다는 의미
@Override
public void run() {
// 내가 실행하고 싶은 코드를 작성 !
} // 프로그램의 entry point
}
// 예전 설명
// java TreadEx_01 => 실행하면..
// JVM이 main method를 호출해서 프로그램을 시작함
// Thread관점에서 다시 설명
// java Thread_01 => 실행하면..
// JVM이 내부적으로 Thread를 하나 생성
// 이 Thread가 main method를 호출해서 실행
// 이 Thread를 main thread라고 부름
// process(프로그램)는 main method가 시작되면 시작하는 거고
// main method가 종료되는 전체 프로그램이 종료됨 => 틀림 !
// 정확하게는 process안에 있는 모든 Thread가 종료되어야지
// process가 종료됨
public class ThreadEx_01 {
public static void main(String[] args) {
// 이 main method는 당연히 하나의 Thread에 의해서 실행되는 method
int result = 10 / 0;
}
}
package sampleproj;
class ThreadEx_01_1 extends Thread {
public ThreadEx_01 () {
}
// 새로운 독립적인 실행 흐름
// 프로그램의 entry point에 준하는 무언가 시작 method가 있다는 의미
@Override
public void run() {
// 내가 실행하고 싶은 코드를 작성 !
// for문 같은 경우
// 1. 집합자료구조를 이용하는 경우 => for~each구문
// for(Stirng s : list) { }
// 2. 원하는 횟수만큼 반복할 경우 => 일반 for문
for(int i=0; i<5; i++) {
System.out.println(this.getName());
}//for()
} // 프로그램의 entry point
}
// 예전 설명
// java TreadEx_01 => 실행하면..
// JVM이 main method를 호출해서 프로그램을 시작함
// Thread관점에서 다시 설명
// java Thread_01 => 실행하면..
// JVM이 내부적으로 Thread를 하나 생성
// 이 Thread가 main method를 호출해서 실행
// 이 Thread를 main thread라고 부름
// process(프로그램)는 main method가 시작되면 시작하는 거고
// main method가 종료되는 전체 프로그램이 종료됨 => 틀림 !
// 정확하게는 process안에 있는 모든 Thread가 종료되어야지
// process가 종료됨
public class ThreadEx_01 {
public static void main(String[] args) {
// 이 main method는 당연히 하나의 Thread에 의해서 실행되는 method
// int result = 10 / 0;
ThreadEx_01_1 t1= new ThreadEx_01_1();
// t1은 Thread instance가 됨
// t1은 현재 객체일 뿐, 아직 동작하지 않고 있음
// 이 thread는 독립적인 실행 흐름을 가지고 있음
// run()안에 그 내용을 기술하고 있음
// 이제 이 thread를 실행시킬거에요
t1.run();
// 이렇게 호출하면.. 단순히 객체의 method를 호출하는 거지
// Thread를 실행시킨 건 아님
// 아하, 이렇게 하는게 아니라 다른 method를 이용해야 함
t1.start(); //run을 찾아가서 호출
// start()를 이용해서 Thread를 실행시킴
System.out.println("main thread 종료");
}
}
package sampleproj;
class ThreadEx_01_1 extends Thread {
public ThreadEx_01() {
}
// 새로운 독립적인 실행 흐름
// 프로그램의 entry point에 준하는 무언가 시작 method가 있다는 의미
@Override
public void run() {
// 내가 실행하고 싶은 코드를 작성 !
// for문 같은 경우
// 1. 집합자료구조를 이용하는 경우 => for~each구문
// for(Stirng s : list) { }
// 2. 원하는 횟수만큼 반복할 경우 => 일반 for문
for(int i=0; i<5; i++) {
System.out.println(this.getName());
}//for()
} // 프로그램의 entry point
}
// 예전 설명
// java TreadEx_01 => 실행하면..
// JVM이 main method를 호출해서 프로그램을 시작함
// Thread관점에서 다시 설명
// java Thread_01 => 실행하면..
// JVM이 내부적으로 Thread를 하나 생성
// 이 Thread가 main method를 호출해서 실행
// 이 Thread를 main thread라고 부름
// process(프로그램)는 main method가 시작되면 시작하는 거고
// main method가 종료되는 전체 프로그램이 종료됨 => 틀림 !
// 정확하게는 process안에 있는 모든 Thread가 종료되어야지
// process가 종료됨
public class ThreadEx_01 {
public static void main(String[] args) {
// 이 main method는 당연히 하나의 Thread에 의해서 실행되는 method
// int result = 10 / 0;
ThreadEx_01_1 t1= new ThreadEx_01_1();
// t1은 Thread instance가 됨
// t1은 현재 객체일 뿐, 아직 동작하지 않고 있음
// 이 thread는 독립적인 실행 흐름을 가지고 있음
// run()안에 그 내용을 기술하고 있음
// 이제 이 thread를 실행시킬거에요
t1.run();
// 이렇게 호출하면.. 단순히 객체의 method를 호출하는 거지
// Thread를 실행시킨 건 아님
// 거의 대부분의 method는 blocking method에요!
// method 수행이 끝나고 return될 때까지 대기!
// 아하, 이렇게 하는게 아니라 다른 method를 이용해야 함
t1.start(); //run을 찾아가서 호출
// start()를 이용해서 Thread를 실행시킴
System.out.println("main thread 종료");
}
}
thread실행
t1.start()
-thread의 실행을 기다리지 않음
-> Thread Scheduler로 가서 언젠가는 실행
예제2)
package sampleproj;
// 이렇게 만든 클래스는 당연히 Thread가 아님
// 단지, Runnable이라는 특별한 interface를 구현한 클래스일 뿐
// 그래서 getName() method를 이용하려면
// 현재 class를 찾아야함.
class ThreadEx_01_2 implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0; i<5; i++) {
System.out.println(Thread.currentThread().getName()); //Thread라는 class의 현재 동작 중인 Thread를 찾는다
}//for()
} // 프로그램의 entry point
}
// 이 밑에 있는 클래스는 당연히 Thread이다. is-a 관계에 의한 !
class ThreadEx_01_1 extends Thread {
public ThreadEx_01_1() {
}
// 새로운 독립적인 실행 흐름
// 프로그램의 entry point에 준하는 무언가 시작 method가 있다는 의미
@Override
public void run() {
// for문 같은 경우
// 1. 집합자료구조를 이용하는 경우 => for~each구문
// for(Stirng s : list) { }
// 2. 원하는 횟수만큼 반복할 경우 => 일반 for문
for(int i=0; i<5; i++) {
System.out.println(this.getName()); //getName은 Thread의 이름을 알아내는 객체
}//for()
} // 프로그램의 entry point
}
// 예전 설명
// java TreadEx_01 => 실행하면..
// JVM이 main method를 호출해서 프로그램을 시작함
// Thread관점에서 다시 설명
// java Thread_01 => 실행하면..
// JVM이 내부적으로 Thread를 하나 생성
// 이 Thread가 main method를 호출해서 실행
// 이 Thread를 main thread라고 부름
// process(프로그램)는 main method가 시작되면 시작하는 거고
// main method가 종료되는 전체 프로그램이 종료됨 => 틀림 !
// 정확하게는 process안에 있는 모든 Thread가 종료되어야지
// process가 종료됨
public class ThreadEx_01 {
public static void main(String[] args) {
// 이 main method는 당연히 하나의 Thread에 의해서 실행되는 method
// int result = 10 / 0;
Runnable r2 = new ThreadEx_01_2(); // Thread가 아님
Thread t2 = new Thread(r2); // Thread가 됨 !
ThreadEx_01_1 t1= new ThreadEx_01_1();
// t1은 Thread instance가 됨
// t1은 현재 객체일 뿐, 아직 동작하지 않고 있음
// 이 thread는 독립적인 실행 흐름을 가지고 있음
// run()안에 그 내용을 기술하고 있음
// 이제 이 thread를 실행시킬거에요
// t1.run();
// 이렇게 호출하면.. 단순히 객체의 method를 호출하는 거지
// Thread를 실행시킨 건 아님
// 거의 대부분의 method는 blocking method에요!
// method 수행이 끝나고 return될 때까지 대기!
// 아하, 이렇게 하는게 아니라 다른 method를 이용해야 함
t1.start(); //run을 찾아가서 호출
t2.start();
// start();는 non-blocking.
// start()를 이용해서 Thread를 실행시킴
System.out.println("main thread 종료");
}
}
System.out.println(Thread.currentThread().getName());
//Thread라는 class의 현재 동작 중인 Thread를 찾는다
run할 때마다 순서가 달라짐
ThreadEx_02_1.java
package sampleproj;
//쉽게 Thread하기 위해 Thread class를 상속받음
class ThreadEx_02_1 extends Thread{
public ThreadEx_02_1() {
}
public ThreadEx_02_1(String name) {
super();
this.setName(name); // Thread 이름을 설정하는 method
// Thread class의 생성자 중 문자열 하나를 받아들이는 생성자를 사용
// 해당문자열로 Thread의 이름 설정
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0; i<5; i++) {
System.out.println(this.getName());
}//for()
}
}
public class ThreadEx_02 {
public static void main(String[] args) {
Thread t1 = new ThreadEx_02_1("My-Thread"); // thread를 만들어서
t1.start(); // thread로 동작시켜 보아요
System.out.println("main thread 종료!");
}
}//
(Thread마다 Stack이 각각 할당됨)
start();
라는 method
새로운 stack(t1 thread)k이 생김
start()를 호출하면 run() 호출
=>stack(main thread)에서 start() 사라짐
적정량의 thread를 이용하면 다중처리할 때 속도가 굉장히 빨라짐
runnable
상태의 thread(start()가 호출된)가 여러개 존재할 때 어떤 thread가 선택될 때는 Thread Scheduler
가 처리
Thread priority(우선순위)
기본은 우선순위값이 5
가장 높은 우선순위 : 10
가장 낮은 우선순위 : 1
ThreadEx_03.java
package sampleproj;
class ThreadEx_03_1 extends Thread{
public ThreadEx_03_1() {
}
public ThreadEx_03_1(String name) {
super(name);
}
@Override
public void run() {
}
}//
public class ThreadEx_03 {
public static void main(String[] args) {
Thread t1 = new ThreadEx_03_1("Thread-01");
Thread t2 = new ThreadEx_03_1("Thread-02");
// 실행시키기 전에 우선순위를 매겨보자
t1.setPriority(1);
t2.setPriority(9);
t1.start();
t2.start();
}
}//
보조
하는 역할의 thread를 지칭ThreadEx_04.java
package sampleproj;
public class ThreadEx_04 implements Runnable{
//field
static boolean autoSave = false;
public static void main(String[] args) {
Thread t = new Thread(new ThreadEx_04());
t.setDaemon(true); //자신을 만든 thread(Main)의 보조 thread가 됨
t.start();
for(int i=0; i<10; i++) {
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
}
if( i == 5) {
autoSave = true;
}//try() end
}//for() end
}
@Override
public void run() {
while(true) {
// Thread를 일정시간동안 재울 거에요
try {
Thread.sleep(3000); //밀리세컨즈 단위 => 3초, class 이름으로 sleep method 바로 호출 => static
//일정 시간동안 thread를 재웠다가,
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(autoSave) {
System.out.println("자동저장 되었어요!");
}
}//while() end
}
}//
Thread.sleep(1000); //현재 Thread를 재움
t.setDaemon(true); //자신을 만든 thread(Main)의 보조 thread가 됨
이 부분 주석 걸면 무한루프됨
: method를 이용해서 thread의 상태가 전이됨
: 지정된 시간만큼 Thread를 재운다
: try~catch
를 이용해 Exception Handling을 해줘야 한다 (강제)
ThreadEx_05.java
package sampleproj;
class ThreadEx_05_1 extends Thread {
@Override
public void run() {
for(int i=0; i<300; i++) {
System.out.println("-");
}
System.out.println("<< Thread 1 종료 >>");
}
}
class ThreadEx_05_2 extends Thread {
@Override
public void run() {
for(int i=0; i<300; i++) {
System.out.println("|");
}
System.out.println("<< Thread 2 종료 >>");
}
}
public class ThreadEx_05 {
public static void main(String[] args) {
Thread t1 = new ThreadEx_05_1();
Thread t2 = new ThreadEx_05_2();
t1.start();
t2.start();
try {
t1.sleep(2000); // Thread.sleep(2000)
} catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("<<main thread 종료>>");
}
}//
package sampleproj;
class ThreadEx_05_1 extends Thread {
@Override
public void run() {
try {
Thread.sleep(3000);
}catch(InterruptedException e){
System.out.println("소리없는 아우성!");
}
for(int i=0; i<300; i++) {
System.out.println("-");
}
System.out.println("<< Thread 1 종료 >>");
}
}
class ThreadEx_05_2 extends Thread {
@Override
public void run() {
for(int i=0; i<300; i++) {
System.out.println("|");
}
System.out.println("<< Thread 2 종료 >>");
}
}
public class ThreadEx_05 {
public static void main(String[] args) {
Thread t1 = new ThreadEx_05_1();
Thread t2 = new ThreadEx_05_2();
t1.start();
t2.start();
System.out.println("<<main thread 종료>>");
}
}//
sleep이 누워있는 이유 :
static
이기 때문
: instance없이 사용할 수 있다
: field, method 앞에 붙을 수 있다
: class명을 이용해서 사용
: instance를 이용해서도 사용할 수 있다
instance/class . field/method()