Java Application은 Main Thread가 main() 메소드를 실행하면서 시작된다.
Main Thread 흐름 안에서 필요에 따라 쓰레드를 만들어 병렬로 코드를 실행할 수 있다.
싱글 스레드 같은 경우 메인 스레드가 종료되면 프로세스도 종료되지만, 멀티 스레드는 메인 스레드가 종료되더라도 실행 중인 스레드가 하나라도 있다면 프로세스는 종료되지 않는다.
- Thread객체를 생성할 때 Runnable 인터페이스를 상속받아 구현한 객체(run 메소드 override 한)를 매개변수로 받는다.
- Thread객체 생성후 start()메소드로 Thead실행
public class MainThreadClass {
public static void main(String[] args) {
Thread subThread1 = new Thread(new TaskRunnable());
Thread subThread2 = new Thread(new TaskRunnable());
Thread subThread3 = new Thread(new TaskRunnable());
subThread1.start();
subThread2.start();
subThread3.start();
}
}
public class TaskRunnable implements Runnable{
@Override
public void run() {
int nSum = 0;
for (int nIdx = 0; nIdx < 5; nIdx++) {
nSum += nIdx;
System.out.println(Thread.currentThread().getName() + " : " + nSum);
}
System.out.println( Thread.currentThread().getName() + " 최종 합 : " + nSum);
}
}
Thread-0 : 0
Thread-2 : 0
Thread-2 : 1
Thread-2 : 3
Thread-1 : 0
Thread-2 : 6
Thread-2 : 10
Thread-0 : 1
Thread-1 : 1
Thread-2 최종 합 : 10
Thread-0 : 3
Thread-1 : 3
Thread-0 : 6
Thread-1 : 6
Thread-0 : 10
Thread-1 : 10
Thread-0 최종 합 : 10
Thread-1 최종 합 : 10
- Thread 클래스를 상속받는다.
- run() 메소드를 override하여 구현한다.
public class MainThreadClass {
public static void main(String[] args) {
Thread subThread1 = new TaskThread();
Thread subThread2 = new TaskThread();
Thread subThread3 = new TaskThread();
subThread1.start();
subThread2.start();
subThread3.start();
}
}
public class TaskThread extends Thread {
@Override
public void run() {
int nSum = 0;
for (int nIdx = 0; nIdx < 5; nIdx++) {
nSum += nIdx;
System.out.println(Thread.currentThread().getName() + " : " + nSum);
}
System.out.println( Thread.currentThread().getName() + " 최종 합 : " + nSum);
}
}
- Main Thread의 보조적인 역할을 수행하는 Thread이다.
- Main Thread가 종료되면 함께 종료된다.
- setDeamon 메소드를 통해 실행시킨다.
public class MainThreadClass {
public static void main(String[] args) throws Exception {
Thread subThread1 = new TaskThread();
Thread subThread2 = new TaskThread();
Thread subThread3 = new TaskThread();
Thread daemonThread = new DaemonThread();
daemonThread.setDaemon(true);
daemonThread.start();
subThread1.start();
subThread2.start();
subThread3.start();
//while문이 없다면 Main Thread가 종료되기 때문에 DaemonThread도 함께 종료된다.
while(true) {
Thread.sleep(100);
}
}
}
public class DaemonThread extends Thread{
@Override
public void run() {
while(true) {
System.out.println("DaemonThread running");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
DaemonThread running
Thread-1 : 0
Thread-2 : 0
Thread-2 : 1
Thread-2 : 3
Thread-1 : 1
Thread-1 : 3
Thread-1 : 6
Thread-1 : 10
Thread-2 : 6
Thread-1 최종 합 : 10
Thread-0 : 0
Thread-2 : 10
Thread-0 : 1
Thread-2 최종 합 : 10
Thread-0 : 3
Thread-0 : 6
Thread-0 : 10
Thread-0 최종 합 : 10
DaemonThread running
DaemonThread running
DaemonThread running
DaemonThread running
DaemonThread running
DaemonThread running
DaemonThread running
DaemonThread running
Multi-Thread 환경에서는 각각의 Thread들이 객체를 공유하며 작업하는 경우가 발생한다.
A Thread와 B Thread가 공유하는 객체가 서로의 작업에 영향을 주어서는 안된다.
동기화 메소드 or 동기화 블록을 이용하여 방지한다.
- 동기화를 너무 남발하게 되면 오히려 성능저하가 발생 할 수 있다.
public class MainThreadClass {
public static void main(String[] args) throws Exception {
ShareClass shareClass = new ShareClass();
for(int nCnt = 0 ; nCnt < 10 ; nCnt++) {
ShareThread shareThread = new ShareThread();
shareThread.setShareClass(shareClass);
shareThread.start();
}
}
}
public class ShareThread extends Thread{
private ShareClass shareClass;
public ShareClass getShareClass() {
return shareClass;
}
public void setShareClass(ShareClass shareClass) {
this.shareClass = shareClass;
}
@Override
public void run() {
shareClass.sum();
}
}
public class ShareClass {
int value;
public void sum() {
System.out.println("결과 : " + this.value);
this.value++;
}
}
결과 : 0
결과 : 1
결과 : 0
결과 : 0
결과 : 0
결과 : 5
결과 : 5
결과 : 7
결과 : 8
결과 : 9
10개의 Thread가 1개의 ShareClass를 공유하고있다.
따라서 실행 결과는 매번 다르게 출력 될 것이다.
public class MainThreadClass {
public static void main(String[] args) throws Exception {
ShareClass shareClass = new ShareClass();
for(int nCnt = 0 ; nCnt < 10 ; nCnt++) {
ShareThread shareThread = new ShareThread();
shareThread.setShareClass(shareClass);
shareThread.start();
}
}
}
public class ShareThread extends Thread{
private ShareClass shareClass;
public ShareClass getShareClass() {
return shareClass;
}
public void setShareClass(ShareClass shareClass) {
this.shareClass = shareClass;
}
@Override
public void run() {
shareClass.sum();
}
}
public class ShareClass {
int value;
public synchronized void sum() {
System.out.println("결과 : " + this.value);
this.value++;
}
}
public class MainThreadClass {
public static void main(String[] args) throws Exception {
ShareClass shareClass = new ShareClass();
for(int nCnt = 0 ; nCnt < 10 ; nCnt++) {
ShareThread shareThread = new ShareThread();
shareThread.setShareClass(shareClass);
shareThread.start();
}
}
}
public class ShareThread extends Thread{
private ShareClass shareClass;
public ShareClass getShareClass() {
return shareClass;
}
public void setShareClass(ShareClass shareClass) {
this.shareClass = shareClass;
}
@Override
public void run() {
synchronized (shareClass) {
shareClass.sum();
}
}
}
public class ShareClass {
int value;
public void sum() {
System.out.println("결과 : " + this.value);
this.value++;
}
}
결과 : 0
결과 : 1
결과 : 2
결과 : 3
결과 : 4
결과 : 5
결과 : 6
결과 : 7
결과 : 8
결과 : 9
annotation-driven / component-scan / annotation-config 차이 정리 (1) | 2022.03.28 |
---|---|
[Spring] ApplicationContext / WebApplicationContext 개념 (0) | 2022.03.21 |
[Spring] IoC 컨테이너 / Bean (0) | 2021.10.14 |
Spring AOP (Proxy) - Logging 적용 (0) | 2021.10.08 |
@Autowired 인터페이스 사용이유 (0) | 2021.10.07 |
댓글 영역