티스토리 뷰
728x90
반응형
Main Thread
- 모든 자바 어플리케이션에서 메인 스레드는 다음과 같은 main 메서드를 통해서 실행하게 됩니다. 메인 메서드가 실행이 되면 코드는 한줄 한줄 순차적으로 시작하게 되고 return을 만나거나 main 메서드의 끝이오면 종료하게 됩니다.
- 이런 main 메서드만 존재하는 상황을 싱글 스레드 어플리케이션이라고 하는데 main 스레드가 종료되면 프로그램 자체도 종료됩니다. main 스레드 구조에서 스레드를 여러개 생성하여 멀티 스레드로 구성할 수 있는데 그림으로 확인해보겠습니다.
- main 스레드가 끝나고도 다른 스레드도 끝나야 프로세스가 종료가 되는데 데몬 스레드는 예외입니다.
public static void main(String[] args) {
System.out.println("Main Thread 실행");
}
데몬 스레드
- 데몬 스레드란 주 스레드의 작업을 돕는 보조적인 역할을 수행하는 스레드입니다. 주 스레드가 종료되면 데몬 스레드는 강제적으로 종료되는데 그 이유는 보조 역할을 수행하므로 주 스레드가 종료되면 데몬 스레드의 존재 의미가 없어지기 때문입니다.
- 크롬이라는 메인 메서드가 실행이 되면서 네이버, 유튜브, 티스토리를 데몬 스레드라고 볼 수 있습니다.
데몬 스레드 설정 true
public class Example {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("유튜브 영상 시청중");
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
}
}
});
thread.setDaemon(true); // 데몬 스레드 설정
thread.start();
System.out.println("메인 메소드 종료");
}
}
데몬 스레드 설정 false
public class Example {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("유튜브 영상 시청중");
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
}
}
});
thread.setDaemon(false); // 데몬 스레드 설정
thread.start();
System.out.println("메인 메소드 종료");
}
}
스레드 동기화
- 싱글 스레드 즉, main 스레드 한개로 구성된 어플리케이션에서는 문제가 되진 않지만 만약 멀티 스레드 상황에서 객체를 생성 한다면 여러개의 스레드가 객체를 건들 수 있는 상황이 생길 수 있습니다. 스레드 A를 사용하던 객체가 만약 스레드 B에 의해 객체의 값이 변경될 수 있다는 의미입니다.
잘못된 예제
public class Ash extends Thread{
String item;
public void setItem(String item) {
this.item = item;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getName() + " - 현재 아이템 : " + this.item);
}
public String getItem() {
return item;
}
}
public class UserA extends Thread{
private Ash ash;
public void setAsh(Ash ash){
this.setName("UserA");
this.ash = ash;
}
@Override
public void run() {
ash.setItem("도란 방패");
}
}
public class UserB extends Thread{
private Ash ash;
public void setAsh(Ash ash){
this.setName("UserB");
this.ash = ash;
}
@Override
public void run() {
ash.setItem("도란 검");
}
}
public class Example {
public static void main(String[] args) {
System.out.println("소환사의 협곡에 오신걸 환영합니다.");
Ash ash = new Ash();
UserA userA = new UserA();
userA.setAsh(ash);
userA.start();
UserB userB = new UserB();
userB.setAsh(ash);
userB.start();
}
}
이러한 상황에서 지금 사용중인 객체(애쉬)를 다른 객체가 접근할 수 없도록 할려면 스레드가 작업이 끝날 때까지 객체에 잠금을 걸어서 다른 스레드가 접근을 할 수 없도록 해야합니다.
synchronized 키워드 사용
- 임계 영역 - 멀티 스레드에서 하나의 스레드만 실행할 수 있는 코드 영역을 임계 영역이라고 합니다. 자바는 이러한 임계 영역을 지정하기 위해서 동기화 메서드와 동기화 블록을 제공합니다. 동기화 메서드를 만드는 방법은 메서드 선언에 synchronized 키워드를 선언하면 됩니다.
public class Ash extends Thread{
String item;
public synchronized void setItem(String item) {
this.item = item;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getName() + " - 현재 아이템 : " + this.item);
}
public String getItem() {
return item;
}
}
데드락
- 스레드 1은 자원 1을 점유하고 있는 상태에서 자원 2가 필요합니다. 스레드 2는 자원 2를 점유하고 있는 상태에서 자원 1이 필요합니다. 하지만 스레드 1은 자원 2가 필요한 상태에서 자원 1을 빌려줄 수 있는 상황도 아니고 스레드 2또한 비슷한 상황입니다.
데몬 스레드 예제
public class ThreadA extends Thread{
Object resource1;
Object resource2;
ThreadA(Object resource1, Object resource2){
this.resource1 = resource1;
this.resource2 = resource2;
}
@Override
public void run() {
synchronized (resource1) {
System.out.println("스레드 1: 자원1 점유 중");
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
System.out.println("스레드 1: 자원2 대기 중");
synchronized (resource2) {
System.out.println("스레드 1 : 자원1 & 2 점유 중");
}
}
}
}
public class ThreadB extends Thread{
Object resource1;
Object resource2;
ThreadB(Object resource1, Object resource2){
this.resource1 = resource1;
this.resource2 = resource2;
}
@Override
public void run() {
synchronized (resource2) {
System.out.println("스레드 2: 자원2 점유 중");
try {
Thread.sleep(500);
} catch (InterruptedException e) {}
System.out.println("스레드 2: 자원1 대기 중");
synchronized (resource1) {
System.out.println("스레드 2: 자원1 & 2 점유 중");
}
}
}
}
public class Example {
public static void main(String[] args) throws InterruptedException {
Object resource1 = new Object();
Object resource2 = new Object();
ThreadA threadA = new ThreadA(resource1, resource2);
ThreadB threadB = new ThreadB(resource1, resource2);
threadA.start();
threadB.start();
Thread.sleep(1000);
System.out.println(threadA.getState());
System.out.println(threadB.getState());
}
}
참고 사이트
728x90
반응형
'JAVA > JAVA기본' 카테고리의 다른 글
JAVA - 어노테이션이란? (0) | 2022.01.29 |
---|---|
JAVA - Enum이란? (0) | 2022.01.29 |
JAVA - Thread란? (0) | 2022.01.27 |
JAVA - Thread 클래스와 Runnable 인터페이스 (0) | 2022.01.27 |
JAVA - 예외 처리(try, catch, throw, throws, finally) (0) | 2022.01.26 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- microkernel architecture
- 서비스 기반 아키텍처
- JDK Dynamic Proxy와 CGLIB의 차이
- spring boot excel download oom
- transactional outbox pattern
- 공간 기반 아키텍처
- service based architecture
- space based architecture
- 트랜잭셔널 아웃박스 패턴 스프링부트
- redis sorted set으로 대기열 구현
- spring boot redisson 분산락 구현
- 자바 백엔드 개발자 추천 도서
- 람다 표현식
- spring boot redisson destributed lock
- spring boot 엑셀 다운로드
- spring boot excel download paging
- polling publisher spring boot
- redis 대기열 구현
- redis sorted set
- spring boot redis 대기열 구현
- @ControllerAdvice
- 레이어드 아키텍처란
- pipe and filter architecture
- java ThreadLocal
- java userThread와 DaemonThread
- transactional outbox pattern spring boot
- spring boot poi excel download
- spring boot redisson sorted set
- pipeline architecture
- 트랜잭셔널 아웃박스 패턴 스프링 부트 예제
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
글 보관함