코드 그라데이션
후발대 21일차 설명 추가 본문
우리가 쓰레드를 만드는 방법이
1. Thread 를 상속받아 만드는 방법과
2. Runnable 이라는 인터페이스를 구현해서 만드는 방법이 있다.
_02_Runnable
package Prac20;
import Prac20.clean.CleanRunnable;
public class _02_Runnable {
public static void main(String[] args) {
CleanRunnable cleanRunnable = new CleanRunnable(); // 객체 생성
Thread thread = new Thread(cleanRunnable);
thread.start(); // run() 아님. CleanRunnable에서 정의되어 있는 동작을 새로운 쓰레드를 만들어서 수행하게 되는 것.
cleanByBoss();
// 실행을 할 때마다 순서가 조금씩 다르게 나올 수 있다. 순서를 확실하게 보장하는 건 아니기 때문이다.
}
// _01_Thread에서 만들었던 메서드와 동일
public static void cleanByBoss() {
System.out.println("--사장 청소 시작--");
for (int i = 1; i <= 10; i+=2) {
System.out.println("(사장) " + i +" 번방 청소 중");
}
System.out.println("--사장 청소 끝--");
}
}
1번 방법과 2번 방법의 결정적인 차이가 무엇인가?
1번은 단일 상속만 가능. 하나의 부모 클래스만 가져야 한다.
2번은 인터페이스가 구현하는 것이므로 extends, implement 동시에 가능
이거 빼고는 기능적으로 동일하다.
_03_Join
package Prac20;
import Prac20.clean.CleanRunnable;
public class _03_Join {
// 사장이 직원 고용해놓고 청소를 시키는데, 얘가 잘 하고 있는지 의심이 드는 상황.
// 그래서 사장이 직원 끝난 후에 자기도 청소를 시작하려고 한다. **
public static void main(String[] args) {
CleanRunnable cleanRunnable = new CleanRunnable();
Thread thread = new Thread(cleanRunnable);
thread.start();
try {
// thread.join(); 이거 지연시간 2.5초 추가
thread.join(2500); // try-catch로 감싸야 한다.
// 사장이 온전히 기다렸다가 하면 직원채용의 의미가 없으니 2.5초만 참자 느낌으로 추가.
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
cleanByBoss();
}
//_01_Thread의 cleanByBoss와 동일.
public static void cleanByBoss() {
System.out.println("--사장 청소 시작--");
for (int i = 1; i <= 10; i+=2) {
System.out.println("(사장) " + i +" 번방 청소 중");
try {
Thread.sleep(1000); //지연, 이것도 try-catch 감싸야.
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("--사장 청소 끝--");
}
}
/**
* join()의 역할
* 쓰레드가 시작해서 종료될 때까지 기다렸다가
* 끝난 후 다음 메서드로 넘어가서 실행되는 것.
*/
CleanThread에 추가
public class CleanRunnable implements Runnable {
@Override
public void run() { // CleanThread에서 만들었던 메서드 그대로임
System.out.println("--직원 청소 시작 (Runnable)~~~");
for (int i = 2; i <= 10; i+=2) {
System.out.println("(직원) " + i +" 번방 청소 중 (Runnable)");
}
// 요기
try {
Thread.sleep(1000); //지연, 이것도 try-catch 감싸야.
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("--직원 청소 끝 (Runnable)--");
}
}
이러면 사장이 온전히 기다리지 않아도 된다.
_04_MultiThread
이번에는 Runnable 내에서 InnerClass를 이용해서 만들어보도록 하겠다.
package Prac20;
public class _04_MultiThread {
// 말 그대로 쓰레드가 두 개 이상인 것(여러 개)
// 사장님이 감독도 해야 하고 자기도 청소도 해야 하니까 매우 비효율성을 느낌.
public static void main(String[] args) {
Runnable cleaner1 = new Runnable() {
@Override
public void run() { //CleanRunnable의 코드를 그대로 가져옴.
System.out.println("--직원1 청소 시작 --"); // 1로 바꾸고, 쓸데 없는 부분 지움
for (int i = 1; i <= 10; i+=2) { // 1번방이므로 1부터 시작
System.out.println("(직원1) " + i +" 번방 청소 중");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("--직원1 청소 끝 --");
}
};
Runnable cleaner2 =() -> { // 이건 람다식을 이용해서 만들어봄.
System.out.println("--직원2 청소 시작 --");
for (int i = 2; i <= 10; i+=2) {
System.out.println("(직원2) " + i +" 번방 청소 중 ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("--직원2 청소 끝 --");
};
// 두 명의 직원을 채용했으니 쓰레드 두 개 생성
Thread cleaner1Thread = new Thread(cleaner1);
Thread cleaner2Thread = new Thread(cleaner2);
cleaner1Thread.start();
cleaner2Thread.start();
}
}
실행하면 왔다갔다 하면서 청소를 수행한다.
_05. 동기화
public class _05_Synchronization {
public static void main(String[] args) {
// Room room = new Room();
Runnable cleaner1 = new Runnable() {
@Override
public void run() { // MultiThread 메서드 그대로 가져오고 시간 지연 부분만 지운다. 반복문도 살짝 수정
System.out.println("--직원1 청소 시작 --");
for (int i = 1; i <= 10; i+=2) {
System.out.println("직원 1) " + i +" 번방 청소 중");
// room.clean("직원1");
}
System.out.println("--직원1 청소 끝 --");
}
};
Runnable cleaner2 =() -> {
System.out.println("--직원2 청소 시작 --");
for (int i = 2; i <= 10; i+=2) {
System.out.println("직원 2) " + i +" 번방 청소 중");
// room.clean("직원2");
}
System.out.println("--직원2 청소 끝 --");
};
Thread cleaner1Thread = new Thread(cleaner1);
Thread cleaner2Thread = new Thread(cleaner2);
cleaner1Thread.start();
cleaner2Thread.start();
}
}
여기서 순서대로 비어있는 방을 청소하게 만들겠다.
Synchronized를 다음과 같이 바꿔주고
package Prac20;
import Prac20.clean.Room;
public class _05_Synchronization {
public static void main(String[] args) {
Room room = new Room();
Runnable cleaner1 = new Runnable() {
@Override
public void run() { // MultiThread 메서드 그대로 가져오고 시간 지연 부분만 지운다. 반복문도 살짝 수정
System.out.println("--직원1 청소 시작 --");
// for (int i = 1; i <= 10; i+=2) {
for (int i = 1; i <= 5; i++) {
// System.out.println("직원 1) " + i +" 번방 청소 중");
room.clean("직원1");
}
System.out.println("--직원1 청소 끝 --");
}
};
Runnable cleaner2 =() -> {
System.out.println("--직원2 청소 시작 --");
// for (int i = 2; i <= 10; i+=2) {
for (int i = 1; i <= 5; i++) {
// System.out.println("직원 2) " + i +" 번방 청소 중");
room.clean("직원2");
}
System.out.println("--직원2 청소 끝 --");
};
Thread cleaner1Thread = new Thread(cleaner1);
Thread cleaner2Thread = new Thread(cleaner2);
cleaner1Thread.start();
cleaner2Thread.start();
}
}
/**
* 두 쓰레드가 동시에 한 리소스에 접근하려고 하면 동시성 문제가 발생해서 똑같이 1번방이 두 번 나오는 이상한 경우도 발생한다.
* 사실 이건 이상한 건 아니다.
*/
Room 클래스도 만들어준다.
public class Room {
public int roomNumber = 1;
// 이 싱크로나이즈드가 중요!!!
synchronized public void clean(String name) { // 직원 누가 청소중인지 받기 위해서 name을 받음
// ex. 직원 1 : 3번방 청소중
System.out.println(name + ": " + roomNumber + "번방 청소중");
roomNumber++;
}
}
추가.
두 개 이상의 쓰레드에서 작업을 하다가 하나가 문제가 생긴다면?
-> 남은 것은 다행히 정상적으로 작동한다.
수정한
_05_Synchronized
package Prac20;
import Prac20.clean.Room;
public class _05_Synchronization {
public static void main(String[] args) {
Room room = new Room();
Runnable cleaner1 = new Runnable() {
@Override
public void run() { // MultiThread 메서드 그대로 가져오고 시간 지연 부분만 지운다. 반복문도 살짝 수정
System.out.println("--직원1 청소 시작 --");
// for (int i = 1; i <= 10; i+=2) {
for (int i = 1; i <= 5; i++) {
// System.out.println("직원 1) " + i +" 번방 청소 중");
room.clean("직원1");
// 사고 났을 때 추가!!!
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if(i==2) {
throw new RuntimeException("못해 먹겠다~~");
}
}
System.out.println("--직원1 청소 끝 --");
}
};
Runnable cleaner2 =() -> {
System.out.println("--직원2 청소 시작 --");
// for (int i = 2; i <= 10; i+=2) {
for (int i = 1; i <= 5; i++) {
// System.out.println("직원 2) " + i +" 번방 청소 중");
room.clean("직원2");
// 사고 났을 때 추가!!! 2222
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("--직원2 청소 끝 --");
};
Thread cleaner1Thread = new Thread(cleaner1);
Thread cleaner2Thread = new Thread(cleaner2);
cleaner1Thread.start();
cleaner2Thread.start();
}
}
이걸 실행시켜보면
이렇게 나온다!
728x90
'Java > 후발대' 카테고리의 다른 글
후발대 22일차 Quiz (0) | 2023.03.07 |
---|---|
후발대 22일차(1) 전체 코드 (0) | 2023.03.07 |
후발대 21일차 전체 코드 (0) | 2023.03.03 |
예외처리 Quiz (0) | 2023.03.03 |
후발대 20일차 설명 추가 (0) | 2023.03.02 |
Comments