Java Thread

  • 하나의 프로세스 안에 여러 개의 스레드가 동시에 작업 수행
  • 스레드 == 하나의 작업단위
  • 자바에서 스레드 구현은 2가지 방법이 있다 : Runnable 인터페이스, Thread 클래스 상속
    • 공통점 : 둘 다 run() 메소드를 오버라이딩하는 방식
    • 차이점 : 인스턴스 생성 방법
      • public class MyThread implements Runnable
        • 해당 클래스를 인스턴스화해서 Thead 생성자에 argument로 넘겨줘야함
        • currentThread() 호출해서 현재 스레드의 참조를 얻어와야 호출 가능
      • public class MyThread extends Thread
        • 상속받은 클래스를 스레드로 사용
        • 스레드 클래스의 method을 바로 사용
  • start() 메소드를 호출하면, JVM은 알아서 스레드를 위한 콜 스택을 만들어주고 context switching을 통해 스레드로 동작하도록 해줌
  • 스레드 상태
    • NEW : 스레드가 생성되고, start()가 호출 X
    • RUNNABLE : 실행 중 or 실행 가능 상태
    • BLOCKED : 동기화 블록에 의해 일시 정지된 상태 (lock 풀릴 때까지 wait)
    • WAITING : 실행가능하지 않은 일시 정지 상태
    • TERMINATED: 스레드 작업이 종료된 상태
  • synchronized를 활용하여 임계 영역(공유 자원에 하나의 스레드만 접근) 설정 가능
  • wait() : 스레드가 lock을 가지고 있으면, lock 권한 반납하고 대기하게 만듦
  • notify() : 대기 상태인 스레드에게 다시 lock 권한을 부여하고 수행하게 만듦

'Language > Java' 카테고리의 다른 글

JVM이란  (0) 2020.11.15

자바 가상 머신(JVM)

  • 자바 애플리케이션(ByteCode)을 클래스 로더를 통해 읽어들여 자바 API와 함께 실행

  • JAVA와 OS 사이에서 중개자 역할 – 따라서 JAVA가 OS에 구애받지 않게 재사용

  • 가장 중요한 메모리 관리(Garbage collection)을 수행

  • 스택 기반의 가상 머신

JVM 구성 = Class loader + Execution engine + GC + Runtime Data Area

  • 클래스 로더 : 클래스(.class)를 로드하고, 링크를 통해 배치

  • 실행 엔진 : 클래스를 실행 / ByteCode -> 기계어로 변환하는2가지 방식

    • 인터프리터 : 명령어 단위로 읽음. 한 줄씩 실행해서 느림

    • JIT (just in time)

      • 인터프리터 방식으로 실행하다가 byte code 전체 컴파일

      • 네이티브 코드로 실행하고 네이티브 코드로 직접 실행

      • 네이티브 코드는 캐시에 보관하므로 컴파일 후 빠르게 수행됨

    • GC : 힙 내의 객체 중 참조되고 있지 않은 객체를 찾아내 메모리 회수 (실제로는 실행 엔진 내부에 존재한다고 봐도 된다)

      • Minor GC
        • 새로 생성된 객체는 Eden 영역에 위치
        • Eden 영역에서 GC가 발생하고 남은 객체는 Survivor 영역(2개) 이동
        • 위 과정 반복하다 계속 살아남은 객체는 계속 참조 – Old 영역 이동
      • Major GC
        • Old 영역의 객체 모두 검사 -> 참조되지 않은 객체 한꺼번에 삭제
        • Major GC가 발생하면 GC 실행 스레드 제외 나머지 스레드 모두 중지
        • GC 작업 이후에 중단 작업 다시 시작
        • Full GC가 일어나는 수초간 모든 Thread가 정지한다면 심각한 장애 발생
  • Runtime Data Area = Method, Heap, Stack, PC register, native method stack

    • 쓰레드가 생성되었을 때 기준으로 메소드, 힙 영역은 모든 쓰레드가 공유 / 스택, PC register, native method stack은 각 쓰레드마다 생성되고 공유 X
    • Method Area : 메소드 영역 (ex> 변수 이름 등 필드 정보, 메소드 정보,static 변수)
    • Heap Area : new 키워드로 생성된 객체와 배열이 생성되는 영역. 메소드 영역에 로드된 클래스만 생성, GC가 참조되지 않는 메모리를 확인하고 제거하는 영역
    • Stack Area : 지역변수, 파라미터, 리턴 값, 임시값 등이 생성되는 영역, 인스턴스 생성시 스택 영역에 생성된 변수 값이 힙 영역에 생성된 객체를 가리키는 것 (메소드 스택)
    • PC register : Thread가 생성될 때마다 생성되는 영역, program counter, 즉, 현재 쓰레드가 실행되는 부분의 주소와 명령을 저장
    • Native method stack : 자바 외 언어로 작성된 네이티브 코드를 위한 메모리 영역(ex> C)

'Language > Java' 카테고리의 다른 글

Java Thread  (0) 2020.11.23

pip install로 파이썬 패키지를 다운로드할 때 -killed 이라며 중지되는 경우가 있다.

 

해결법은

pip install <package> --no-cache-dir

호이스팅 (Hoisting)

호이스팅이란 함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것이다.

오해가 있을 수 있는 부분인데, 실제로 코드가 끌어올려지는 것은 아니며, javascript Parser 내부적으로 컴파일 단계에서 끌어올려 처리하는 것이다.

catName('Chloe');

function catName(name) {
    console.log("My cat's name is " + name);
}

위 코드에서 함수를 작성하기 전에 함수를 호출하였지만, 코드는 정상적으로 작동한다.

var 변수 선언함수선언문에서만 호이스팅이 일어난다.
var foo2 = function(){...} 형식의 함수표현식let/const 변수 선언에서는 호이스팅이 발생하지 않는다.

var 변수/함수의 초기화(할당)가 아닌 선언만 끌어올린다. 변수를 선언한 뒤에 나중에 초기화시켜서 사용한다면, 그 값은 아래 예시와 같이 undefined로 지정된다.

var x = 1; // Initialize x
var y; // Declare y
console.log(x + ' ' + y); // '1 undefined'
y = 2; // Initialize y

코드의 가독성과 유지보수를 위해 호이스팅이 일어나지 않게 해야하며, let/const 를 사용함으로써 이 문제를 방지할 수 있다.

ES6를 모든 브라우저가 지원하는 것이 아니므로, ES5로 babel 등을 통해 트랜스컴파일을 진행해야 하고 이것이 var의 동작에 대해 FE 개발자가 이해하고 있어야 하는 이유이다.

Reference

'Language > JavaScript' 카테고리의 다른 글

자바스크립트 Primitive(원시값)  (0) 2020.06.13
자바스크립트 클로저  (0) 2020.06.12
CORS  (0) 2020.05.04
SPA란  (0) 2020.01.07

Primitive

Javascript에서 원시값(primitive, 원시 자료형)이란 객체도 아니고 메서드도 아닌 data이다.
총 7개의 원시 자료형이 존재한다.

  • string
  • number
  • bigint
  • boolean
  • null
  • undefined
  • symbol (ES16에서 추가)

모든 primitive는 불변이다. primitive 자체와 primitive을 할당한 변수를 혼동하지 않아야 한다. 변수는 새로운 값을 다시 할당할 수 있지만, 이미 생성한 primitive는 객체, 배열, 함수와 달리 변형이 불가하다. 여기서 객체, 배열, 함수를 원시값과 구별하여 참조 타입(reference type) 이라고 부른다.

var numberPrimitive = 10;
var booleanPrimitive = false;
var stringPrimitivie = 'string boy';

위 코드에서 예를 들어 설명을 하자면, 대입되는 오른쪽 값이 primitive로 보면 되고, 실제 작동할 때는 변수를 이용하여 작업을 한다. 원시값이 변하지 않는 이유는, 원시값에 직접 작업하는 것이 아니라, 원본을 건드리지 않고 복사본을 가져와 작업을 하는 것이기 때문.

  • 각각의 값은 모두 스택에 저장된다
  • 변수 자체가 하나의 값을 가진다.
  • 인자가 전달될 때 call by value의 형태로 넘어간다.
  • primitive type의 값은 immutable하다.

null과 undefined를 제외하고, 모든 primitive는 원시값을 래핑한 객체를 가진다.

  • 문자열 원시값을 위한 String 객체
  • 숫자 원시값을 위한 Number 객체
  • 빅인트 원시값을 위한 BigInt 객체
  • 불리언 원시값을 위한 Boolean 객체
  • 심볼 원시값을 위한 Symbol 객체

Reference

'Language > JavaScript' 카테고리의 다른 글

호이스팅 (Hoisting)  (0) 2020.06.14
자바스크립트 클로저  (0) 2020.06.12
CORS  (0) 2020.05.04
SPA란  (0) 2020.01.07

클로저(Closure)

클로저는 함수의 실행이 끝난 뒤에도 함수에 선언된 변수의 값을 접근할 수 있는 자바스크립트의 성질이다. 바로 예시로 들어가보자.

function addCounter() {
    var counter = 0;

    return function () {
        return counter++;
    };
}

addCounter();
console.log(counter);

위 코드는 오류가 나는 코드이다. addCounter() 함수의 실행이 끝난 시점에서 counter라는 변수는 더이상 접근을 할 수 없는 상태이다. 함수 안에 선언한 변수는 함수 안에서만 유효 범위를 갖기 때문이다.

function addCounter() {
    var counter = 0;

    return function () {
        return counter++;
    };
}

var add = addCounter();
add();
add();
add();

아까와는 달리 이 코드는 오류 없이 실행된다. addCounter() 함수가 반환한 함수를 add라는 변수에 담아놓았기 때문에 add 자체가 함수처럼 동작하는 것이다.

addCounter()의 반환 함수는 자신이 생성된 렉시컬 스코프에서 벗어나 global에서 add라는 이름으로 호출이 되었다. 이런 add 와 같은 함수를 클로저라고 부른다.

addCounter() 의 렉시컬 스코프에서 생성된 instance는 addCounter(); 수행이 끝난 후에 Garbage Collector가 회수해야 하는데, 사실은 그렇게 작동하지 않는다. 위에서 설명한 것과 같이, addCounter()의 반환 함수는 렉시컬 환경인 addCounter()의 렉시컬 환경을 계속 참조하고 있고, global에서 add가 해당 함수를 계속 참조하고 있기 때문이다. 이 때문에 클로저를 남용하게 되면 메모리 이슈가 생기게 된다.

클로저를 응용하여 자바스크립트에 없는 private 변수를 구현할 수 있다.

function counter() {
    var _count = 0;

    return function () {
        _count += 1;

        return _count;
    };
}
var counterFirst = counter();
console.log(counterFirst());
console.log(counterFirst());

위와 같이 구현하면, _count 변수는 외부에서 접근할 수 없는 방법이 없다. counter() 함수 내에서만 접근할 수 있는 private 변수가 구현된 것이다.

Reference

'Language > JavaScript' 카테고리의 다른 글

호이스팅 (Hoisting)  (0) 2020.06.14
자바스크립트 Primitive(원시값)  (0) 2020.06.13
CORS  (0) 2020.05.04
SPA란  (0) 2020.01.07

+ Recent posts