프로세스란 단순히 실행 중인 프로그램(program)이라고 할 수 있습니다.
즉, 사용자가 작성한 프로그램이 운영체제에 의해 메모리 공간을 할당받아 실행 중인 것을 말합니다.
이러한 프로세스는 프로그램에 사용되는 데이터와 메모리 등의 자원 그리고 스레드로 구성됩니다.
스레드(thread)란 프로세스(process) 내에서 실제로 작업을 수행하는 주체를 의미합니다.
모든 프로세스에는 한 개 이상의 스레드가 존재하여 작업을 수행합니다.
또한, 두 개 이상의 스레드를 가지는 프로세스를 멀티스레드 프로세스(multi-threaded process)라고 합니다.
자바의 모든 애플리케이션은 메인 스레드가 main()메서드를 실행하면서 시작합니다.
메인 스레드는 main() 메서드의 첫 코드부터 아래로 순차적으로 실행하고, main() 메서드의 마지막 코드를 실행하거나 return문을 만나면 실행이 종료됩니다.
멀티 스레드로 실행하는 애플리케이션을 개발할면 먼저 몇 개의 작업을 병ㄹ려로 실행할지 결정하고 각 작업별로 스레드를 생성해야 합니다.
두 방법 모두 스레드를 통해 작업하고 싶은 내용을 run()메서드에 작성하면 됩니다.
package Thread;
class ThreadWithClass extends Thread {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(getName()); //현재 실행 중인 스레드의 이름을 반환한다.
try {
Thread.sleep(10); //0.01초간 스레드를 멈춘다.
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class ThreadWithRunnable implements Runnable {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName());
//현재 실행중인 스레드의 이름을 반환한다.
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Thread01{
public static void main(String[] args) {
ThreadWithClass thread1 = new ThreadWithClass(); //Thread 클래스를 상속받는 방법
Thread thread2 = new Thread(new ThreadWithRunnable()); //Runnable인터페이스를 구현하는 방법
thread1.start(); //스레드의 실행
thread2.start(); //스레드의 실행
}
}
위 예제의 실행 결과를 살펴보면, 생성된 스레드가 서로 번걸아가며 실행되고 있는 것을 확인 할 수 있습니다.
Runnable 인터페이스는 몸체가 없는 메서드인 run()메서드 단 하나만을 가지는 간단한 인터페이스입니다.
예를 들어 리그오브레전드라는 게임을 생각해보면 블리츠크랭크는 상대를 끌어오는 스킬은 Q스킬이 끝나기 전까지는 움직이거나 다른 모션을 취할수 없다.
즉 스레드를 사용하지 않은 경우에는 한 줄이 완전히 끝난 후에 다음 줄로 넘어가게 된다.
반면에 아리라는 챔피언을 보면 QWER을 순서대로 눌러주었는데 스킬의 완료 여부와 상관 없이 다른 스킬을 계속 수행하는 것이 보인다.
즉 스레드를 사용하면 한번에 여러 동작을 수행할 수 있다는 것이다.
package Thread;
public class Blitzcrank {
String skill_name;
public Blitzcrank(String cmd) {
this.skill_name = cmd;
}
public void run(){
System.out.println("시전한 스킬: "+skill_name);
for(int i=0; i<=3; i++){
System.out.println(skill_name +"스킬을 "+i+"초간 시전 중입니다.");
}
System.out.println("시전 끝난 스킬 : "+skill_name);
}
public static void main(String[] args) {
String[] cmd =new String[]{"Q","W","E"}; //Q,W,E를 넣고 순서대로 수행할 것
for(int i=0; i<= cmd.length; i++){
Blitzcrank b = new Blitzcrank(cmd[i]); //객체화
b.run();
}
}
}
먼저 스레드를 사용하지 않은 일반 코드인데
String타입의 배열 cmd에 Q,W,E를 넣어주고
Blitzcrank를 개개화 한뒤 run()메서드를 수행해 주니
Q,W,E 순으로 코드가 진행되는 것이 보인다.
package Thread;
public class Ahri extends Thread{
String skill_name;
public Ahri(String cmd){
this.skill_name =cmd;
}
public void run(){
System.out.println("시전할 스킬: "+skill_name);
for(int i=1; i<=3; i++){
System.out.println(skill_name+ " 스킬을 " +i+"초간 시전 중입니다.");
}
System.out.println("시전 끝난 스킬 : "+skill_name);
}
public static void main(String[] args) {
String[]cmd =new String[]{"Q","W","E"};
for(int i=0; i<=cmd.length; i++){
Ahri a = new Ahri(cmd[i]);
a.start();
}
}
}
여기서는 extends Thread를 통해 사용했다.
보면 거의 동일한 코드지만 다른 점은 Thread는 상속받고 start()메서드를 수행 시run()메서드를 수행한다는 차이가 있따.
여기서 실행된 코드를 보면
a.start 는 순서대로 수행하되 run()은 들어오는 순서대로가 아닌 동시에 수행되는 것이 보인다.
쓰레드를 사용하면 동시에 여러개의 코드를 수행할 수 있으므로 동시에 엄청난 양이 들어오는 채팅서비스나 공장의 경우에는 하나씩 처리하면 엄청난 시간이 걸리기 때문에 쓰레드를 사용하여 많은 양도 한번에 처리할 수 있다.
다만 쓰레드를 사용시 주의할 점이자 단점은 쓰레드로 하번에 많은 코드들을 수행할수록 컴퓨터에 부하가 심해지며 쓰레드 수행 도중 내게 필요한 자원을 남이 가지고 있고 남은 남에게 필요한 자원을 내가 가지고 있어서 서로 무한정 대기하는 교착상태( Deadlock) 문제가 있으므로 이에 주의해야한다.