-
11,12일차 - Thread프로그래밍 언어/자바(JAVA) 2024. 2. 6. 15:54
Thread는 무엇인가?
Thread, 프로그램을 움직이는 원동력
Thread : 프로세스 안에서 할당받은 자원을 이용하는 실행 흐름의 단위
■ 하나의 프로세스에 최소 한개의 쓰레드가 존재한다
■ 프로세스간에는 메모리를 공유하지 않는다
■ 같은 프로세스 안에 있는 쓰레드끼리는 메모리를 공유한다
Main Thread 는 자신을 위해 일할 Work Thread 를 생성할 수 있다
이것을 Multi Thread 라고 한다
분신술 처럼 CPU가 굉장히 빠르게 일처리를 해주고 있어 여러 쓰레드가 생긴것 처럼 보인다
Thread 의 생성 방법
1. Runnable Interface 구현
■ Runnable Interface 를 구현하는 Class 를 하나 만든다
■ Class 에 Thread의 run() 메서드를 오버라이딩하여 쓰레드의 작업을 정의한다!
■ 구현된 인터페이스를 쓰레드 생성시 생성자 파라미터로 넣어준다
■ Main Thread 에서 멀티 스레드(WorkThread)를 호출한다
public class WorkThread implements Runnable { @Override public void run() { // 쓰레드가 할일을 run() 메소드를 오버라이딩하여 정의한다 for (int i = 0; i < 5; i++) { try { System.out.println("워크 쓰레드가 하는 일 - " + i); Thread.sleep(i); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws Exception { // Main Thread 에서 멀티 스레드(WorkThread)를 동작시킨다 Thread th = new Thread(new WorkThread()); th.start(); }
2. Thread Class 상속
■ 쓰레드가 수행할 일을 정의할 클래스에 Thread 를 상속받는다
■ Class 에 Thread의 run() 메서드를 오버라이딩하여 쓰레드의 작업을 정의한다!
■ Main Thread 에서 멀티 스레드(WorkThread)를 호출한다
public class Job extends Thread { @Override public void run() { for (int i = 0; i<5; i++) { System.out.println("extends : work thread..."); try { Thread.sleep(30); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public static void main(String[] args) { // 앞선 코드와 동일하지만 다형성을 이용해 상속받은 Job 을 Thread 객체에 // 넣을 수 있다 Thread th = new Job(); th.start(); }
Thread 의 경쟁상태, 공유된 자원(메모리)에 변경하는 상황
■ Thread 끼리 메모리가 공유되어 객체 간의 데이터 간섭이 일어나는 것이 원인이다
■ 경쟁 상태는 두 개 이상의 쓰레드가 공유된 자원(변수, 자료구조 등)에 동시에 접근하고, 그 자원을 변경하려고 할 때 발생한다
public class Computer { private int score; public void setScore(int score) { this.score = score; try { Thread.sleep(2000); // 2초간 자리를 비우는 동안 누군가가 이 점수를 건드릴 수 있다 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " : " + this.score); } } public class User1 extends Thread { private Computer com; public User1(Computer computer) { setName("User 1"); this.com = computer; } @Override public void run() { com.setScore(500); } } public class User2 extends Thread { private Computer com; public User2(Computer computer) { setName("User 2"); this.com = computer; } @Override public void run() { com.setScore(200); } } public class PcRoom { public static void main(String[] args) { // 공용 컴퓨터 Computer com = new Computer(); // 컴퓨터를 각 유저에게 전달 User1 user1 = new User1(com); User2 user2 = new User2(com); user1.start(); // 500점으로 만든다 user2.start(); // 200점으로 만든다 } }
■ 코드의 순서를 아래의 표로 정리해봤다
출력 결과 사용 중인 쓰레드 쓰레드 실행문 User1 com 의 score 변수 값을 500으로 변경 Thread.sleep(2000);
- 2초 동안 user1 쓰레드를 잠에 들게 한다User2 com 의 score 변수 값을 200으로 변경 Thread.sleep(2000);
- 2초 동안 user2 쓰레드를 잠에 들게 한다200 User1 잠에서 깨어난 user1 쓰레드가 com 의 score 값을 출력한다 200 User2 잠에서 깨어난 user2 쓰레드가 com 의 score 값을 출력한다 Synchronized(동기화), 내 작업이 다 끝나기 전에는 아무도 접근하지 못하게 하는 것이다
1. 메서드 앞에서 막는 방법
// synchronized : 싱크로라이즈드 붙은 메소드는 한번에 하나의 쓰레드만 실행 할 수 있다 // synchronized method public synchronized void setScore(int score) { this.score = score; try { Thread.sleep(2000); // 2초간 자리를 비우는 동안 누군가가 이 점수를 건드릴 수 있다 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " : " + this.score); }
2. 메서드 범위를 지정해서 안에서 막는 방법
// synchronized block : 메서드 안의 특정 영역 진입을 막는다 public void setScore(int score) { synchronized (this) { this.score = score; try { Thread.sleep(2000); // 2초간 자리를 비우는 동안 누군가가 이 점수를 건드릴 수 있다 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " : " + this.score); } }
RUNNABLE 이 많이 출력되는 이유
■ CPU 는 한번에 하나의 쓰레드의 작업을 처리하는데 작업을 한번에 다 처리하지 않고 일정 시간만 처리하고 남은 작업량은 대기시킨다
□ (라운드 로빈 방식으로 처리)
■ 그렇다 보니깐 작업중이지 않은 나머지 쓰레드는 RUNNABLE 상태를 가진다
Thread 제어
Sleep() 특정 쓰레드를 일정 시간동안 일시 정지 시킨다
Yield() 특정 쓰레드에게 CPU의 제어권을 양보하는 '기회' 를 준다
■ 현실 세계 : 할머니 여기 앉으세요.. (3..2..1 의자에 앉음)
■ 쓰레드 세계 : 할망구 빨리 안 앉으면 내가 앉을 거야
Wait() 누군가가 notify() 해줄 때까지 쉬어준다
Notify() 노티파이 자고 있는 쓰레드 중 하나를 대기시킨다 (1:1)
■ 본인을 제외한 나머지 쓰레드들 중 하나를 대기 시킨다
NotifyAll() 다 깨운다
■ wait 을 먼저 하면 그 누구도 일어나지 못하기 때문에 반드시 notify 로 교대자를 먼저 깨워야한다
오늘 배운 쓰레드 제어 방법!!!!!!!!!
1. sleep()
2. yield() 완벽한 순서 제어는 아니엿다 기회를 줄뿐
3. join() 쓰레드가 끝날때까지 기다리기
4. notify() 과 wait()
5. stopflag과 interrupt 방식StopFlag 방식, 반복문의 종료조건을 Boolean 변수를 넣어 쓰레드를 종료한다
Interrupt 방식, 반복문을 탈출 조건을 Thread 의 인터럽트 신호가 오면 탈출하여 쓰레드를 종료한다
Demon Thread, 내 할일이 끝나지 않아도 메인쓰레드가 끝나면 같이 끝난다
■ WorkThread 에서 Demon Thread 로 지정하는것이다
■ MainThread 가 종료되면 실행중이던 말던 같이 종료된다
동기 vs 비동기의 차이
■ 작업이 순차적으로 실행되는 것을 의미하고 한 작업이 완료될 때까지 다음 작업은 대기 상태이다
■ 반면에 비동기는 작업이 독립적으로 실행되는 것을 의미한다. 한 작업이 완료되지 않아도 다른 작업이 실행될 수 있다
동기 쓰레드 Main Work 실행 상태 Running Runnable Runnable Running Running Runnable 비동기 쓰레드 Main Work 실행 상태 Running Runnable Running Terminated Thread Pool, 쓰레드는 하나 만드는데 1-2MB 메모리를 만드는데 100개 만들면 100-200MB 날라간다 그래서 쓰레드 풀이라는 개념이 등장했다
Thread Pool 의 역할
■ 스케이트를 타러 갔는데 한명이라면 오래 걸리지 않고 만들어서 탈 수 있다
1. 시간이 오래걸림
2. 신발을 오랫동안 안쓰면 버려야할 수 있다
그래서 스케이트 대여소 다 쓰면 신발을 반납하면된다
■ 미리 만들어놓은 쓰레드를 빌려주고 쓰는 방식으로 사용한다
1. 아무것도 만들지 않고 사람이 몰릴때 확 많이 만들자
2. 신발을 최소치를 정해서 미리 만들어두자
대여할때에는 어디에 쓸게 하고 알려주고 쓰레드를 쓴다
Thread Pool 생성
■ newFixedThreadPool() : 고정된 수의 쓰레드를 사용하는 쓰레드 풀을 생성한다
■ newCachedThreadPool() : 필요에 따라 쓰레드를 생성하고, 60초 동안 사용되지 않은 쓰레드는 제거된다
Thread Pool 에서 쓰레드를 빌려 작업을 실행
1. Runnable 구현 클래스, 리턴하지 않고 쓰레드가 처리할 작업을 정의한다
■ execute(Runnable) 작업 처리 결과를 받지 못한다
2. Callable 구현 클래스, call 하니깐 return 이 있어야 한다
■ submit(Callable) Future 로 작업 처리 결과를 반환된다
■ submit(Runnable) <?> 써서 어떤 타입이 나올지 모르니 ? 타입으로 정해둔다
3. Runnable 구현 클래스, 리턴하지 않고 Future 형태로 내보낸다
■ callable, runnable 둘다 매개변수로 입력 받을 수 있다
■ Future<?> 으로 Runnable 을 입력 받아 fu.get() 을 받을 수 있다
Thread Pool 종료
■ shutdown() : 전체 쓰레드가 모두 작업이 끝나면 쓰레드 풀을 종료한다
■ shutdownNow() : 쓰레드 풀을 강제 종료한다 쓰레드의 작업 여부는 신경쓰지 않는다
■ awaitTermination(대기시간, 대기시간 단위) : shutdown() 메소드 호출 이후 끝나지 않은 쓰레드가 있다면 강제 종료시켜 false 를 반환한다
Thread Pool Blocking
■ Thread Pool 에서 Submit() 메서드에서 Future 객체로 반환받는다
■ Future 객체에서 get() 메서드로 join과 같은 역할을 수행한다
■ 쓰레드가 모두 처리할때까지 기다렸다가 처리 결과를 내보낸다
2월 6일 질문..
1. 스트림이 뭐였죠?
스트림은 바이트 기반의 데이터를 입출력하는 통로이다
2. 스트림이 문자 기반, 바이트 기반에서 읽어들이는것은 뭐엿쭁?
문자기반으로 읽어오는 Reader, 바이트는 Stream 으로 읽어온다
3. FileInputStream 과 BufferedInputStream 의 부모의 클래스는 무엇인가요
InputStream
4. OutputStream이 ???
5. 보조스트림 뭔가요?
보조스트림은 다른 스트림을 받아들여 추가적인 기능을 제공하는 역할을 한다
6. 보조스트림이 어떤 방식으로 사용되는지?
주스트림을 보조스트림의 매개변수로 입력하여 보조스트림을 생성한다
7. 보조스트림중에서 버퍼아웃스트림은 어떤 역할을 담당하나요?
속도 향상을 위해서 버퍼드아웃스트림을 사용한다
8. 오브젝트아웃스트림은 어따가 사용하는지
오브젝트아웃스트림은 자바의 Object 를 자바 고유 데이터로 직렬화하여 쓰는 보조스트림이다. 역직렬화는 오브젝트인풋스트림을 사용한다
9. 직렬화 역직렬화의 개념
직렬화는 Object를 여러 조각으로 쪼개서 전송하고 serialize 인터페이스가 설명서 역할을 하여 조각을 다시 합쳐 데이터를 읽어올 수 있다
10. 역직렬화를 할때 시리얼라이즈 인터페이스 어떤 역할을 하는지
쪼개진 조각을 맞추는 설명서 역할을 한다
11. properties 는 무엇인가요
properties 는 키와 값 쌍으로 이루어진 클래스로, 주로 설정 정보를 저장하고 관리할 수 있다
12. JAVA IO와 NIO 차이점
IO 는 버퍼 없이 스트림을 사용하고, NIO 는 버퍼가 내장된 채널을 사용한다는 것이 가장 큰 차이점이다
13. 쓰레드는 뭔데
쓰레드는 어떤 프로세스를 실행하게 해주는 원동력이다
14. 프로세스와 쓰레드의 차이
프로세스들 간에 메모리를 공유하지 않지만 쓰레드는 한 프로세스 안에 메모리를 같이 공유하고 있어 서로의 상태를 알고 있다
15. workthread 뭔가요
메인 쓰레드가 자신을 위해 일할 쓰레드들을 생성한것을 말한다
16. 쓰레드 생성 방법 두가지
A. Runnable Interface 로 오버라이딩해 구현한 클래스를 메인 쓰레드에서 객체를 생성해 호출하여 쓰레드를 생성한다
B. Thread Class 를 오버라이딩해 상속 받은 클래스를 메인 쓰레드에서 객체를 생성해 호출하여 쓰레드를 생성한다
17. 동기화는 뭔가요?
동기화는 어느 한 쓰레드가 작업하고 있다면 다른 나머지 쓰레드들은 작업이 끝나길 기다리고, 끝난 후 나머지 쓰레들이 작업을 시작한다
객체화 하지 않고 메소드 호출
■ Thread 상속 받은 WorkThread 클래스에서는 부모의 final 메소드를 객체화하지 않고 호출 할 수 있다
public class Thread implements Runnable { public final String getName() { return name; } } public class WorkThread extends Thread { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(getName() + " 스레드가 출력한 내용"); } } }
클래스 다이어그램 작성법
의존 (< - - - - ), 어떤 클래스가 다른 클래스를 참조하는 것
연관 (<--------), 다른 객체의 참조를 가지는 필드 변수를 의미한다
객체화 시킨놈을 클래스 변수에 저장하면 실선
그게 아니고 객체를 사용하고 버리면 점선
'프로그래밍 언어 > 자바(JAVA)' 카테고리의 다른 글
복습 1일차-(클래스) (0) 2024.02.14 13일차 - 네트워크(자바 끝~) (0) 2024.02.08 4일차 - 배열 (0) 2024.02.05 3일차 - 조건문, 반복 (0) 2024.02.05 2일차-연산자 (0) 2024.02.05