코드스테이츠 백엔드 부트캠프 19일차 [Java 심화(Effective)-3]

wish17·2023년 1월 10일
0
post-thumbnail

Section 1 - Java 심화(Effective)

스레드(Thread)

프로세스(Process)와 스레드(Thread)

프로세스 = 실행 중인 애플리케이션
데이터, 컴퓨터 자원, 그리고 스레드로 구성

스레드 = 하나의 코드 실행 흐름
데이터와 애플리케이션이 확보한 자원을 활용하여 소스 코드를 실행한다.

메인 스레드(Main thread)

자바 애플리케이션 실행 시 가장 먼저 실행되는 main메서드를 실행시켜주는 스레드

멀티 스레드(Multi-Thread)

  • 멀티 스레드 프로세스 =여러 개의 스레드를 가진 프로세스

    • 하나의 프로세스는 여러 개의 스레드를 가질 수 있다.
  • 멀티 스레딩 = 여러 스레드가 동시에 작업을 수행하는 것

스레드의 생성과 실행

작업 스레드 생성과 실행

스레드가 처리할 작업은 클래스 내부, run()메서드 내부에 작성해야 한다.

  • run() 메서드
    • Runnable 인터페이스와 Thread 클래스에 정의되어 있음

작업 스레드를 생성, 실행 방법

  • Runnable 인터페이스를 구현한 객체에서 run()을 구현하여 스레드를 생성하고 실행
  • Thread 클래스를 상속 받은 하위 클래스에서 run()을 구현하여 스레드를 생성하고 실행

Runnable 인터페이스를 구현한 객체에서 run()을 구현하여 스레드를 생성하고 실행하는 방법

public class Main {
    public static void main(String[] args) {

        // Runnable 인터페이스를 구현한 객체 생성
        Runnable task1 = new ThreadTask1();

        // Runnable 구현 객체를 인자로 전달하면서 Thread 클래스를 인스턴스화하여 스레드를 생성
        Thread thread1 = new Thread(task1);

        // 위의 두 줄을 아래와 같이 한 줄로 축약할 수도 있다.
        // Thread thread1 = new Thread(new ThreadTask1());

        // 작업 스레드를 실행시켜, run() 내부의 코드를 처리한다.
        thread1.start();

        // 반복문 추가
        for (int i = 0; i < 100; i++) {
            System.out.print("M");
            if(i%25==0) {
                System.out.println("");
            }
        }
    }
}

class ThreadTask1 implements Runnable {
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.print("J");
            if(i%25==0) {
                System.out.println("");
            }
        }
    }
}


// 출력

M
MMMMMMMMMMMJ
JJJJJJJJJJMMMMMMMMMMMMMM
MJJJJJJJJJJJJJJJ
JJJJJJJJJJJJJJJJJJMMMMMMMMMMMMMMMMMMMMMMJJJJJJJ
JJJJJJJJJJJJJJJMM
MMMMMMMMMMMMMJJJJMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMJJJJJJ
JJJJJJJJJJJJJJJJJJJJJJJJ

출력에서
M = 메인 스레드의 반복문에서 출력
J = 작업 스레드의 반복문에서 출력한 것이다.

메인 스레드와 작업 스레드가 동시에 병렬로 실행되어 두 문자가 섞인 것을 확인할 수 있었다.
(cf. 매 실행마다 출력값이 다를 수 있다.)

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

ublic class ThreadExample2 {
    public static void main(String[] args) {

        ThreadTask2 thread2 = new ThreadTask2();

        // 작업 스레드를 실행시켜, run() 내부의 코드를 처리하도록 합니다. 
        thread2.start();

        // 반복문 추가
        for (int i = 0; i < 100; i++) {
            System.out.print("@");
        }
    }
}

class ThreadTask2 extends Thread {
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.print("#");
        }
    }
}

익명 객체를 사용하여 스레드 생성하고 실행하기

public class ThreadExample1 {
    public static void main(String[] args) {
				
        // 익명 Runnable 구현 객체를 활용하여 스레드 생성
        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.print("#");
                }
            }
        });

        thread1.start();

        for (int i = 0; i < 100; i++) {
            System.out.print("@");
        }
    }
}

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

public class ThreadExample2 {
    public static void main(String[] args) {

        // 익명 Thread 하위 객체를 활용한 스레드 생성
        Thread thread2 = new Thread() {
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.print("#");
                }
            }
        };

        thread2.start();

        for (int i = 0; i < 100; i++) {
            System.out.print("@");
        }
    }
}

스레드의 이름

메인스레드(이름: main)를 제외하고 추가적으로 생성한 스레드는 기본적으로 “Thread-n”이라는 이름을 가진다.

  • 스레드의_참조값.getName()로 스레드 이름 조회 가능

  • 스레드의_참조값.setName()로 스레드 이름 설정 가능

  • Thread.currentThread()로 스레드 인스턴스의 주소값 사용하기 가능

public class Main {
    public static void main(String[] args) {

        //스레드 생성
        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                System.out.println("thread1의 이름 = " + Thread.currentThread().getName());
            }
        });

        thread1.start();

        //이름 조회
        System.out.println("thread1.getName() = " + thread1.getName());
        //이름 설정
        thread1.setName("Thread name is wish");
        //바꾼 이름 조회
        System.out.println("thread1의 바뀐 이름 = " + thread1.getName());
        //스레드 인스턴스의 주소값을 통해 스레드이름 조회
        System.out.println(Thread.currentThread().getName());
    }
}

//출력
thread1.getName() = Thread-0
thread1의 이름 = Thread-0
thread1의 바뀐 이름 = Thread name is wish
main

스레드의 동기화

두개 이상의 스레드가 동일한 데이터를 공유하게 되어 문제가 발생할 수 있다.
(cf. 이때 발생하는 문제는 어떤 원인으로 어떤 오류가 날지 추측하기 어렵다.)

이러한 문제가 발생하지 않게 하는 것이 스레드 동기화다.

임계 영역(Critical section)과 락(Lock)

  • 임계 영역 : 오로지 하나의 스레드만 코드를 실행할 수 있는 코드 영역
    • synchronized 키워드를 사용해 설정가능
  • 락: 임계 영역을 포함하고 있는 객체에 접근할 수 있는 권한

자바 가상 머신(Java Virtual Machine)

JVM = 자바로 작성한 소스 코드를 해석해 실행하는 별도의 프로그램

  • 자바의 운영체제로부터 독립적인 특징이 JVM을 통해 구현된다.
    (자바 Application과 os사이의 통역가 역할을 해줌)


자료출처

JVM 구조

자료출처

자바 실행순서

코드작성
-> 실행
-> 컴파일( .java 확장자 소스코드 -> .class 확장자 바이트 코드 파일로 변환)
-> JVM(운영 체제로 부터 메모리[Rumtime Data Area] 할당받음)
-> JVM(클래스 로더[Class Loader]가 바이트 코드 파일을 런타임 데이터 영역에 적재시킴)
-> 실행 엔진(Execution Engine)이 런타임 데이터 영역에 적재된 바이트 코드를 실행


JVM 메모리 구조

자료출처

JVM Stack

  • 프로그램 실행 시 임시로 할당했다가 바로 소멸되는 특성의 데이터가 저장됨
  • 호출된 Method의 매개변수, 지역변수, 리턴값 등을 임시로 저장하는 곳

Heap

  • JVM 작동시 자동 생성
  • 객체나 인스턴스 변수, 배열이 저장
  • 객체를 저장하는 가상 메모리 공간
  • 세 부분으로 나뉨 (Permanent, New/Young, Old)

나머지는 자료출처에서 보자.

Garbage Collection

프로그램에서 더 이상 사용하지 않는 객체를 찾아 삭제하거나 제거하여 메모리를 확보하는 것

0개의 댓글