19Days) Java 심화(2) - Stream 연습문제 풀이, Thread(스레드), JVM(자바 가상 머신)

nacSeo (낙서)·2022년 11월 15일
0

◉ 학습목표

1. Stream 개념을 적용시켜 연습문제를 풀어낼 수 있다.
2. Thread의 개념을 이해하고 직접 활용해볼 수 있다.
3. JVM이 왜 필요한 지 알고 Stack과 Heap메모리와 관련지어 이해할 수 있다.
  1. Stream 연습문제 풀이 (코플릿)

⦿ 학습내용

☞ Stream 연습문제 풀이 (코플릿)

✔︎ .collect(Collectors.toList()); : 리스트 형태로 만드는 최종 연산

✔︎ .toArray(String[]::new); : String 배열로 최종 연산

✔︎ .filter(n->n.startsWith() : 첫 번째 요소 찾기 (중간 연산)

✔︎ .getAsInt() : int값을 반환 (객체가 없으면 NoSuchElementException 발생시킴)

✔︎ .mapToInt(String::length) : 문자열 배열 각 요소의 길이를 구함

✔︎ Stream.concat(stream1, stream2) : 두 개의 스트림을 합침

  1. 스레드 (Thread)

⦿ 학습내용

☞ 스레드 (Thread) 개념

✔︎ 프로그램(Program) : 코드의 집합, 명령어의 집합
✔︎ 프로세스(Process) : 실행 중인 프로그램(애플리케이션)
✔︎ 스레드(Thread) : 코드의 실행 흐름
✔︎ 메인 스레드(Main Thread) : 메인 메서드를 실행
✔︎ 싱글 스레드 애플리케이션 : 자바에서 하나의 메인 메서드만 가지고 있을 때
✔︎ 싱글 스레드 프로세스 : 싱글 스레드 애플리케이션을 실행
✔︎ 멀티 스레드 애플리케이션 : 메인 스레드에 다른 작업 스레드가 존재
✔︎ 멀티 스레드 프로세스 : 멀티 스레드 애플리케이션을 실행
✔︎ 멀티 스레딩 : 여러 스레드가 동시에 작업하는 것

☞ 스레드의 생성과 실행

✔︎ 스레드를 생성하려면 반드시 Runnable 인터페이스 구현해야 함
✔︎ Thread 클래스를 상속받는 하위 클래스에서 오버라이딩으로 사용하더라도, Thread 클래스 안에 이미 Runnable 인터페이스가 존재함
✔︎ 스레드의 생성과 실행 방법
① Runnable 인터페이스를 구현한 객체에서 run()을 구현하여 스레드를 생성∙실행하는 방법

public class ThreadExample1 {
	public static void main(String[] args) {
    	// 스레드 생성
    	Runnable task1 = new ThreadTask1();
        Thread thread1 = new Thread(task1);
        
        // 스레드 실행
        thread1.start();	
        
        for (int i=0; i<10; i++) {
        	System.out.print("N");
        }
    }
}

//Runnable 인터페이스를 구현한 객체에서 `run()`을 구현
class ThreadTask1 implements Runnable {
	public void run() {
    	for (int i=0; i<10; i++) {
        	System.out.print("Y");
        }
    }
}

② Thread 클래스를 상속받은 하위 클래스에서 run()을 구현하여 스레드를 생성∙실행하는 방법

public class ThreadExample2 {
	public static void main(String[] args) {
    	
        // 스레드 생성
        ThreadTask2 thread2 = new ThreadTask2();
        
        //스레드 실행
        thread2.start();
        
        for (int i=0; i<10; i++) {
        	System.out.print("N")
        }
    }
}

// Thread 클래스를 상속받은 하위 클래스에서 `run()` 구현
class ThreadTask2 extends Thread {
	public void run() {
    	for (int i=0; i<10; i++) {
        	System.out.print("Y");
        }
    }
}

✔︎ 익명 객체를 사용하여 스레드를 생성하고 실행 (클래스 따로 정의 ❌)
① Runnable 익명 구현 객체를 활용한 스레드 생성 및 실행

public class ThreadExample1 {
	public static void main(String[] args) {
    
    	// 스레드 생성
        Thread thread1 = new Thread(new Runnable() {
        	public void run() {
            	for (int i=0; i<10; i++) {
                	System.out.print("Y");
                }
            }
        });
        
        // 스레드 실행
        thread1.start();
        
        for (int i=0; i<10; i++) {
        	System.out.print("N");
        }
    }
}

② Thread 익명 하위 객체를 활용한 스레드 생성 및 실행

public class ThreadExample2 {
	public static void main(String[] args) {
    
    	// 스레드 생성
        Thread thread2 = new Thread() {
        	public void run() {
            	for (int i=0; i<10; i++) {
                	System.out.print("Y");
                }
            }
        };
        
        // 스레드 실행
        thread2.start();
        
        for (int i=0; i<10; i++) {
        	System.out.print("N");
        }
    }
}

☞ 스레드의 이름

✔︎ 메인 스레드 이름 : main
✔︎ 추가 생성 스레드 이름 : Thread-n
✔︎ 스레드 이름 조회 : 스레드의_참조값.getName()
✔︎ 스레드 이름 설정 : 스레드의_참조값.setName()
✔︎ 실행중인 스레드의 주소값 : currentThread

☞ 스레드 동기화

✔︎ 멀티 스레드 프로세스의 경우, 두 스레드가 동일한 데이터를 공유하게 되는 문제 발생 가능 💥
✔︎ 스레드 동기화 : 두 가지 스레드가 하나의 객체를 공유할 때는 하나의 스레드씩 처리
✔︎ 임계 영역 : 오로지 하나의 스레드만 코드를 실행할 수 있는 코드 영역
✔︎ 락 : 임계 영역을 포함하고 있는 객체에 접근할 수 있는 권한
✔︎ 어떤 코드가 임계영역에서 실행되려면 락을 얻어야 함 → syjnchronized 키워드 사용
① 메서드 전체를 임계 영역으로 지정

public synchronized boolean withdraw(int money) {	// sychronized 끼워넣기
	// 생략
}

② 특정 영역을 임계 영역으로 지정

public boolean withdraw(int money) {
	synchronized (this) {			// synchronized (공유_객체) {안으로_코드_옮겨줌}
    // 생략
}

☞ 스레드의 상태와 실행 제어

✔︎ start() 메서드
✓ 직접 바로 실행시켜주는 메서드가 아니라, 실행 대기 상태(runnable)로 만들어줌
✓ 직접 실행시키는 건 운영체제의 스케줄러
→ 스레드에는 상태라는 것이 존재
→ 스레드의 상태를 바꿀 수 있는 메서드들이 존재
✔︎ sleep(long milliSecond) : milliSecond 동안 스레드를 잠시 멈춤
ex. Thread.sleep(1000);
✔︎ sleep()에 의해 일시 정지된 스레드가 복귀하는 경우
✓ 인자로 전달한 시간 만큼의 시간이 경과했을 때
interrupt()를 호출했을 때
※ sleep()을 사용할 때는 반드시 try ~ catch문을 사용하여 예외처리 해주어야 함
✔︎ interrupt() : 일시 중지 상태인 스레드를 실행 대기 상태로 복귀시킴
✔︎ yield() : 다른 스레드에게 실행을 양보
✔︎ join() : 다른 스레드의 작업이 끝날 때까지 기다림
✔︎ wait(), notify() : 스레드 간 협업에 사용

  1. 자바 가상 머신 (JVM)

⦿ 학습내용

☞ 자바 가상 머신 (JVM)

✔︎ 자바로 작성한 소스 코드를 해석해 실행하는 별도의 프로그램
✔︎ 자바 프로그램과 운영체제 사이에서 일종의 통역가 역할 수행
✔︎ 자바가 운영체제에서 독립적이라는 이유

☞ 스택(Stack) 영역

✔︎ LIFO(Last In First Out) 구조 : 마지막으로 들어간 데이터가 가장 먼저 나옴
✔︎ 참조변수, 매개변수, 지역변수, 리턴값 및 연산시 일어나는 값 임시 저장

☞ 힙(Heap) 영역

✔︎ JVM에는 단 하나의 Heap영역 존재
✔︎ 객체, 인스턴스 변수, 배열이 저장됨
✔︎ 실제 객체의 값이 저장되는 공간
Stack 영역의 참조 변수를 통해 Heap 영역에 존재하는 객체를 다룸

☞ Garbage Collection

✔︎ 가비지 컬렉션 : 프로그램에서 더 이상 사용하지 않는 객체를 찾아 삭제하거나 제거하여 메모리를 확보
✔︎ Minor GC : Heap영역 중 새롭게 생성된 객체가 할당되고, 많은 객체가 생성되었다 사라지는 Young영역에서 활동하는 가비지 컬렉터
✔︎ Major GC : Heap영역 중 Young영역에서 상태를 유지하고 살아남은 객체들이 복사되는 Old영역에서 활동하는 가비지 컬렉터 (Young영역보다 크게 할당되고 크기가 큼, 가비지는 적게 발생)
✔︎ 가비지 켈렉션 실행 단계
① Stop The World : 가비지 실행을 위해 JVM이 애플리케이션의 실행을 멈추는 단계
② Mark and Sweep : Mark를 통해 사용되는 메모리와 사용하지 않는 메모리를 식별하고, Sweep을 통해 사용되지 않는 메모리를 해제하는 작업을 수행

◉ 느낀 점

☞ 스트림 연습문제를 풀며 사용하려하니 정말 낯설고 손에 안익는다 🥲 반복에 반복이 절실히 필요..
스레드라는 단어를 정말 많이 들어봤는데 이제서야 얕게나마 이해가 간다! 파면 팔수록 어렵다는데 그 전에 이번 기회를 통하여 확실히 기초를 다잡고 가야겠다..! 여러 예제들을 인텔리제이를 통해 입력해보고 응용해보는 기회를 가져야지 ,,, 😤

◉ 내일의 키워드

・ 기술 면접
・ 미니 잡서칭
・ Section_1 회고
profile
백엔드 개발자 김창하입니다 🙇‍♂️

0개의 댓글