본문 바로가기
Backend boot camp/Session1

[JAVA] 심화 - Thread, JVM

by orioncsy 2022. 9. 19.

0. 스레드

개요

학습 목표

  • 스레드란
  • 싱글 스레드 VS 멀티 스레드
  • 스레드 생성 방법
  • 스레드 실행 및 동기화
  • 스레드 상태 및 제어

스레드란?

프로세스

  • 운영체제가 할당한 메모리에 실행 중인 애플리케이션
  • 데이터, 컴퓨터 자원, 스레드로 구성

스레드

  • 프로세스 내 소스 코드의 실행 흐름
  • 멀티 스레드로 동시 작업 실행 가능

메인 스레드(Main thread)

  • 자바 애플리케이션에서 메인 메서드를 가장 먼저 실행
  • 메인 메서드 안의 코드를 실행시키는 메인 스레드
  • 메인 스레드만 사용하면 싱글 스레드

멀티 스레드(Multi thread)

  • 여러 개의 스레드가 동시 작업
  • 하나의 애플리케이션 내 여러 작업을 동시에 실행

스레드 생성과 실행

Runnable 인터페이스에서 run() 메서드를 구현하여 스레드 생성

public class Main{
    public static void main(String[] args) {
        Thread thread1 = new Thread(new Task());
//        Runnable runnable = new Task();
//        Thread thread1=new Thread(runnable); // 따로 선언하여 사용 가능
        thread1.start(); // thread 작업 시작
        for(int i=0; i<200; i++)
            System.out.print("main_thread");
    }
}
class Task implements Runnable{
    @Override
    public void run() {
        for(int i=0; i<200; i++)
            System.out.print("thread1");
    }
}
//실행 결과 병렬적으로 작업을 처리하는 것 확인

익명 클래스를 활용하여 Runnable 인터페이스에서 run() 메서드를 구현

public class Main{
    public static void main(String[] args) {
        Thread thread1 = new Thread(new Runnable(){
            @Override
            public void run() {
                for(int i=0; i<200; i++)
                    System.out.print("thread1");
            }
        });
//        Runnable runnable = new Task();
//        Thread thread1=new Thread(runnable); // 따로 선언하여 사용 가능
        thread1.start(); // thread 작업 시작
        for(int i=0; i<200; i++)
            System.out.print("main_thread");
    }
}

Thread 클래스를 상속 받은 하위 클래스에서 run() 구현하여 스레드 생성

public class Main{
    public static void main(String[] args) {
        Thread thread2=new Task2();
        thread2.start();
        for(int i=0; i<200; i++)
            System.out.print("main_thread");
    }
}
class Task2 extends Thread{
    @Override
    public void run() {
        for(int i=0; i<200; i++)
            System.out.print("thread1");
    }
}

Thread 익명 하위 객체를 이용한 스레드 생성

public class Main{
    public static void main(String[] args) {
        Thread thread2=new Task2(){
					@Override
			    public void run() {
		        for(int i=0; i<200; i++)
	            System.out.print("thread1");
			    }
				};
        thread2.start();
        for(int i=0; i<200; i++)
            System.out.print("main_thread");
		}
}

스레드 이름

  • 메인 스레드는 main, 그 외의 스레드는 thread-n의 이름을 가진다

스레드 이름 조회

public class Main{
    public static void main(String[] args) {
        Thread thread1 = new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println("get thread name..");
            }
        });
        thread1.start(); // thread 작업 시작
        System.out.println(thread1.getName());
    }
}

스레드 이름 설정

public class Main{
    public static void main(String[] args) {
        Thread thread1 = new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println("set thread name");
            }
        });
        thread1.start(); // thread 작업 시작
        thread1.setName("0th thread");
        System.out.println(thread1.getName());
    }
}

스레드 인스턴스의 주소값

public class Main{
    public static void main(String[] args) {
        Thread thread1 = new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
        thread1.start(); // thread 작업 시작
        System.out.println(Thread.currentThread().getName());
				//현재 thread의 인스턴스 주소값을 반환(Thread.currentThread())
    }
}

스레드 동기화

  • 스레드 동기화
    • 두 개 이상의 스레드가 같은 데이터를 공유하여 발생하는 문제를 해결
    • synchronized()로 임계 영역(critical section)을 설정하고 하나의 스레드만 실행 가능한 구역으로 만든다
    • 해당 임계 영역에 접근할 수 있는 권한인 lock을 획득한 스레드만 임계 영역을 실행 가능
  • 스레드 동기화 방식
    • 메서드 전체를 임계 영역으로 설정
      • public synchronized void method(){…}
    • 특정 영역을 임계 영역으로 설정
      • synchronized(this){ … }

스레드 상태 및 제어

  • .start()는 스레드를 실행 대기 상태로 올린다
  • 스레드의 상태가 존재하고 제어하는 메서드들 존재

스레드 상태

  • 스레드 생성(new)
  • 실행 대기(runnable)
  • 실행
  • 일시정지
  • 소멸

스레스 실행 제어 메서드

  • static void sleep(long millisecond) : millisecond 동안 스레드 일시정지
    • 실행 대기에서 일시정지 상태로 전환
  • void interrupt() : 실행 대기로 복귀
    • wait, sleep, join으로 일시 정지한 스레드를 실행 대기 상태로 복귀
    • wait, sleep, join의 예외가 발생하여 일시정지 해제
    • 예제
    public class Main{
        public static void main(String[] args) {
            Thread thread1 = new Thread(new Runnable(){
                @Override
                public void run() {
                    try{
                        while(true){
                            Thread.sleep(1000);
                            // 1초 단위로 계속해서 thread를 TIMED_WAITING상태로 만든다
                        }
                    }
                    catch (Exception e){
                        System.out.println("interrupted now");
                        //interrupt로 대기 상태로 복귀되었을 때 실행
                    }
                }
            });
    
            System.out.println(thread1.getState()); // 스레드 생성(NEW) 상태
            thread1.start(); // thread 작업 시작
    
            while(true){
                if(thread1.getState() == Thread.State.TIMED_WAITING) {
                    System.out.println(thread1.getState());
                    break; // 계속해서 TIMED_WAITING상태로 존재한다
                }
            }
            thread1.interrupt(); // thread를 실행 대기(RUNNABLE)상태로 복귀
            while(true){
                if(thread1.getState() == Thread.State.RUNNABLE) {
                    System.out.println(thread1.getState());
                    break;
                }
            } // 복귀 상태 RUNNABLE 상태 출력
            while(true) {
                if (thread1.getState() == Thread.State.TERMINATED) {
                    System.out.println(thread1.getState());
                    break;
                }
            }//실행되고 나서 소멸 상태 출력
        }
    }
    
  • static void yield() : 다른 스레드에게 실행 양보
    • 실행 상태에서 다른 스레드에게 실행을 양보
    • 예제
    public void run(){
    	while(true){
    		if(...){
    		...
    		}
    		else
    			Thread.yield(); //(무의미한 반복문이 반복될 때 다른 스레드에게 실행 양보)
    	}
    }
    
  • void join() / void join(long millisecond) : 다른 스레드의 작업이 끝날 때까지 기다림
    • sleep()과 유사하지만 join()은 특정 스레드에 대하여 작동하는 인스턴스 메서드다
  • notify(), wait() : 두 스레드가 교대로 작업할 때 사용
    • notify()로 다른 스레드를 실행 대기 상태로 두고 wait로 자신을 일시정지로 바꾸며 교대
    public class Main{
        public static void main(String[] args) {
            Working working = new Working();
            Thread1 thread1= new Thread1(working);
            Thread2 thread2= new Thread2(working);
    
            thread1.start();
            thread2.start();
            //출력 결과는 this is method1/ this is method2가 교대하며 20번씩 반복
        }
    
    }
    class Working{
        public synchronized void method1(){
            System.out.println("this is method1");
            notify();
            try {
                wait();
            } catch (Exception e) {};
        }
        public synchronized void method2(){
            System.out.println("this is method2");
            notify();
            try {
                wait();
            } catch (Exception e) {};
        }
    }
    class Thread1 extends Thread{
        Working working;
    
        public Thread1(Working working) {
            this.working = working;
        }
    
        @Override
        public void run() {
            for(int i=0; i<20; i++)
                working.method1();
        }
    }
    
    class Thread2 extends Thread{
        Working working;
    
        public Thread2(Working working) {
            this.working = working;
        }
    
        @Override
        public void run() {
            for(int i=0; i<20; i++)
                working.method2();
        }
    }
    

1. 자바 가상 머신(Java Virtual Machine)

개요

Write once, run anywhere

  • JAVA는 JVM을 통해 운영체제에 독립적으로 프로그래밍 가능

학습 목표

  • JVM이란?
  • JVM 메모리 구조
  • Garbage Collection

JVM이란?

Java Virtual Machine

  • 자바로 작성된 소스 코드를 실행하는 프로그램
  • 프로그램이 실행되기 위해서 컴퓨터 자원을 요청
    • 운영체제마다 방식이 다름
    • java는 JVM을 통해 각 운영체제에 맞게 변환시켜준다

JVM 구조

  • java source code(.java)
  • java Byte code(.class file)
    • java 파일을 javac라는 명령어로 java compiler를 사용하여 변환
  • JVM
    • runtime data area : 소스 코드에 필요한 메모리 할당
    • class loader : java Byte code를 runtime data area에 적재
    • execution engine : runtime data area에 적재된 byte code를 실행
      • interpreter : 코드를 한 줄씩 기계어로 번역하고 실행
      • JIT(just-in-time) Compiler : 전체 코드를 기계어로 번역하고 실행
      • 기본적으로 interpreter를 사용하고 반복되는 코드를 JIT로 실행

Stack과 Heap

Java 메모리 구조

  • Runtime data area
    • method area
    • heap area
    • stack area
    • PC register
    • Native method stack

Stack

  • LIFO(Last In First Out) 방식의 자료구조
  • JVM 내 stack
    • 메서드가 실행되면 method frame이 생성
    • 매겨변수, 지역변수, 연산 값 등이 스택 형태로 저장
    • 메서드가 종료될 때 역순으로 제거된다

Heap

  • JVM 내 하나의 heap 영역 존재
    • 객체, 인스턴스 변수, 배열 저장
  • 인스턴스를 생성하여 저장하는 장소
    • 그 주소 값을 stack에 참조 변수로 저장

Garbage Collection

Garbage Collection

  • 메모리 자동 관리 프로세스
  • 더 이상 사용하지 않는 객체를 삭제
  • 아무도 참조하고 있지 않는 객체를 제거

동작 방식

  • 힙 영역 내에 객체가 얼마나 살아있냐에 따라 young, old 방식 존재
    • Young 영역
      • 새롭게 생성된 객체가 할당되고 생성, 삭제가 반복되는 곳
      • Minor GC라고 부름
    • Old 영역
      • 상태를 유지하고 남은 객체들이 복사되는 곳으로 크기가 크고 삭제할 데이터가 적다
      • Major GC라고 부름
  • 기본적인 동작 방식
    • Stop The World
      • GC를 실행하기 위한 스레드를 제외한 모든 애플리케이션 실행을 중단
      • GC가 완료되면 재개
    • Mark and Sweap
      • 메모리가 사용되고 있는지 식별(Mark)하고
      • 사용되지 않는다면 제거(Sweep)한다

'Backend boot camp > Session1' 카테고리의 다른 글

Session1 회고  (1) 2022.09.19
[JAVA] 심화(Effective)  (0) 2022.09.14
[JAVA] 컬렉션(Collection)  (0) 2022.09.06
[JAVA] 객체 지향 프로그래밍 심화  (0) 2022.09.06
[JAVA] 객체 지향 프로그래밍 기초  (0) 2022.09.06