싱글 쓰레드(Thread)
- 하나의 쓰레드가 작업을 순차적으로 처리하기 때문에 특정 작업이 종료된 후에 다음 작업을 수행함
- 동시에 여러 작업을 수행할 수 없다.
A작업 => B작업 => C작업 순서로 진행
멀티 쓰레드(Multi Thread)
하나의 프로세스(Process) 내에서 2개 이상의 쓰레드가 2개 이상의 작업을 동시에 수행할 수 있도록 하는 것.
실제 동시에 수행되는 것은 아니고 아주 빠른 속도로 2개 이상의 작업을 번갈아가며 수행하기 때문에
사용자 입장에서는 동시에 수행되는 것 처럼 보임.
채팅 메세지를 송수신하면서 파일을 송수신하는 것 처럼
java.lang.Tread 클래스 또는 java.lang.Runnable 인터페이스를 활용
1) Thread 클래스를 상속받는 서브클래스를 정의하여 멀티쓰레딩으로 처리할 메서드를 run() 메서드에 구현하는 방법
=> 해당 서브클래스 인스턴스 생성 후 start() 메서드를 호출하여 멀티쓰레딩으로 처리할 코드를 실행하도록 함
=> 주의! run() 메서드를 호출하지 않도록!!!!!
방법 1. Thread 클래스를 상속받는 서브클래스를 정의
class MyThread extends Thread {
String name;
int count;
public MyThread(String name, int count) {
super();
this.name = name;
this.count = count;
}
// 멀티쓰레딩으로 처리할 작업은 Thread 클래스의 run() 메서드를
// 오버라이딩하여 run() 메서드 내부에 기술
@Override
public void run() {
for(int i = 1; i <= count; i++) {
System.out.println(name + " : " + i);
}
}
//인스턴스 생성
MyThread mt1 = new MyThread("A작업", 500000);
MyThread mt2 = new MyThread("B작업", 500000);
MyThread mt3 = new MyThread("C작업", 100000);
// 주의! run() 메서드를 호출하게 되면 멀티쓰레딩이 수행되지 않는다!
// mt1.run();
// mt2.run();
// mt3.run();
// 반드시 start() 메서드를 호출하여 간접적으로 run() 메서드를 호출
mt1.start();
mt2.start();
mt3.start();
// A작업, B작업, C작업이 번갈아가면서 실행되며
// 각 작업의 실행 순서는 항상 다를 수 있다!
// => 즉, 실행 결과는 항상 다르다.
방법 2. java.lang.Runnable 인터페이스를 구현하여 멀티쓰레딩으로 처리할 메서드를 run 메서드에 구현
현재 다른 클래스를 상속 중인 서브클래스에서 멀티쓰레딩 구현 시
Thread 클래스를 다중 상속할 수 없으므로 Runnable 인터페이스를 구현(인터페이스는 다중 상속 가능하니께)
run() 메서드 오버라이딩 후 멀티쓰레딩 코드 기술 과정은 동일함
Runnable 인터페이스 내에 start() 메서드가 없으므로 Thread 클래스 인스턴스 생성자에 Runnable 구현체를 전달하고
Thread 클래스의 start() 메서드를 호출하여 간접적으로 Thread 실행
class A {}
// 멀티쓰레딩으로 작업을 처리하기 위한 방법2
// => 기존의 다른 클래스를 상속받는 중인 클래스의 경우
// Thread 클래스를 추가로 상속받지 못하므로
// 대신, Runnable 인터페이스를 상속받아 구현하는 서브클래스를 정의
class YourThread extends A implements Runnable {
String name;
int count;
public YourThread(String name, int count) {
super();
this.name = name;
this.count = count;
}
// Runnable 인터페이스를 구현한 구현체 클래스에서는
// 추상메서드 run() 메서드를 반드시 구현해야하며
// 멀티쓰레딩으로 처리할 작업을 run() 메서드 내부에 기술
@Override
public void run() {
for(int i = 1; i <= count; i++) {
System.out.println(name + " : " + i);
}
}
원래는 start()로 메서드 호출해서 멀티쓰레딩을 수행해야 하나,
Runnable 인터페이스 내부에는 start 메서드가 존재하지 않는다.....
그래서 대신 구현체를 전달해서 간접적으로 실행해야 함
YourThread yt1 = new YourThread("A작업", 500000);
YourThread yt2 = new YourThread("B작업", 500000);
YourThread yt3 = new YourThread("C작업", 100000);
// start() 메서드를 가진 Thread 클래스의 인스턴스 생성 시
// 생성자 파라미터에 Runnable 인터페이스 구현체의 인스턴스를 전달하고
// Thread 인스턴스의 start() 메서드를 통해 간접적으로 run() 메서드 호출
Thread t1 = new Thread(yt1);
Thread t2 = new Thread(yt2);
Thread t3 = new Thread(yt3);
t1.start();
t2.start();
t3.start();
멀티쓰레드를 구현한 구현체 클래스를 외부에서 정의하는 대신
내부 클래스 형태로 구현하여 전용 클래스로 사용할 수 있다.
Thread 로
1) 2단계로 구현된 내부 클래스 사용 시
=> 구현체 클래스 인스턴스 생성 필요
// 2단계로 구현된 내부클래스 사용 시
// => 구현체 클래스 인스턴스 생성 필요
// InnerYourThread iyt = new InnerYourThread("A작업", 500000);
// Thread t = new Thread(iyt);
// t.start();
// => 2단계 방식
private class InnerYourThread extends A implements Runnable {
String name;
int count;
public InnerYourThread(String name, int count) {
super();
this.name = name;
this.count = count;
}
// Runnable 인터페이스를 구현한 구현체 클래스에서는
// 추상메서드 run() 메서드를 반드시 구현해야하며
// 멀티쓰레딩으로 처리할 작업을 run() 메서드 내부에 기술
@Override
public void run() {
for(int i = 1; i <= count; i++) {
System.out.println(name + " : " + i);
}
}
}
2) 3단계로 구현된 내부 클래스 사용 시
=> 이미 참조변수와 인스턴스까지 생성되어 있으므로 바로 사용 가능
=> Thread 클래스의 인스턴스 생성 및 생성자에 Runnable 객체 전달
Thread t = new Thread(runnable);
t.start();
Thread 클래스의 참조변수 선언 없이 임시 객체 형태로 바로 사용할 경우
new Thread(runnable).start(); 하면된다.
// 3단계로 구현된 내부클래스 사용 시
// => 이미 참조변수와 인스턴스까지 생성되어 있으므로 바로 사용 가능
// => Thread 클래스의 인스턴스 생성 및 생성자에 Runnable 객체 전달
// Thread t = new Thread(runnable);
// t.start();
// Thread 클래스의 참조변수 선언 없이 임시 객체 형태로 바로 사용
// => new Thread(Runnable객체).start() 형태로 사용2
new Thread(runnable).start();
}
// 3단계 방식으로 구현 - 익명 내부 클래스 형태로 정의
// => Runnable 인터페이스 이름을 직접 사용하면서
// 인스턴스 생성 및 추상메서드 구현까지 모두 한꺼번에 처리
Runnable runnable = new Runnable() {
@Override
public void run() {
for(int i = 1; i <= 500000; i++) {
System.out.println("A작업" + " : " + i);
}
}
};
main() 메서드도 main 쓰레드에서 관리하므로
다른 쓰레드가 동작한다면 두 쓰레드가 번갈아가며 수행된다.
public void multiThread() {
// 3단계 방식으로 구현 - 익명 내부 클래스 형태로 정의
// => Runnable 인터페이스 이름을 직접 사용하면서
// 인스턴스 생성 및 추상메서드 구현까지 모두 한꺼번에 처리
Runnable runnable = new Runnable() {
@Override
public void run() {
for(int i = 1; i <= 500000; i++) {
System.out.println("A작업" + " : " + i);
}
}
};
// Thread 임시객체 생성자에 Runnable 객체 전달 후 바로 start() 메서드 호출
new Thread(runnable).start();
// 이 때, Runnable 타입 변수 runnable 은 Thread 객체에서 한 번 사용 후
// 더 이상 사용되지 않는다.
// 따라서, 별도의 변수 선언 없이 Runnable 객체도 임시 객체 형태로
// Thread 생성자 파라미터에서 바로 구현까지 수행할 수 있다 = 4단계
// => 1회성 객체는 참조변수 없이 인스턴스 생성 및 추상메서드 구현까지 수행
new Thread(new Runnable() {
@Override
public void run() {
for(int i = 1; i <= 500000; i++) {
System.out.println("B작업" + " : " + i);
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for(int i = 1; i <= 500000; i++) {
System.out.println("C작업" + " : " + i);
}
}
}).start();
}
'develop > Java' 카테고리의 다른 글
Wrapper 클래스 (0) | 2021.04.18 |
---|---|
enum 타입 (0) | 2021.04.12 |
예외(Exception) (0) | 2021.04.12 |
중첩 클래스 (0) | 2021.04.12 |
제네릭(Generic, 일반화) (1) | 2021.04.05 |