[Java] 4. Exception, Process, Thread(1)

Nam_JU·2022년 7월 17일
0

KaKao Cloud School

목록 보기
9/19
post-thumbnail


Error(에러) vs Exception(예외)

  • Checked Exception : 반드시 예외처리를 해야함
  • UnChecked Exception : 컴파일이 이상없이 실행이 된다

Error

  • Error : 에러란 컴퓨터 하드웨어의 오동작 또는 고장으로 인해 프로그램에 이상이 생겼거나 JVM실행에 문제가 생겼을 경우 발생하는 것을 말한다.

    프로그램이 스스로 해결할 수 없는 에러
    (Program이 지속할 수 없는 오류)

Exception

  • Exception: 예외란 사용자의 잘못된 조작 또는 개발자의 잘못된 코딩으로 인해 발생하는 프로그램 오류를 말한다. 예외는 예외처리를 통해 프로그램이 종료되지 않고 정상적으로 작동되게 만들어 줄 수 있다.

    프로그램적으로 해결할 수 있는 오류
    (자바는 클래스의 집합이기 때문에 정의를 해두었다)

프로그램을 실행하다가 프로그램이 정상적으로 돌아가지 않는 상황에 처하면 JVM이 현재 오류에 대한 정보를 모아서 객체(인스턴스)를 만들어서 준다 → 자동생성됨

만약 이 객체를 해결하지 못하면 프로그램이 자동 종료. 처리되면 종료되지 않고 지속적인 수행이 가능하다.


자바의 Try - Catch

Exception이 발생하게 되면 프로그램이 즉시 멈추게 된다

public class Main {
    public static void main(String[] args) {
        System.out.println("프로그램 시작!");
        int result = 10/0; //오류가 발생
        System.out.println("프로그램 종료");
    }
}


여기서 try-catch를 사용하게 되면 프로그램이 멈추지 않고 돌아가는 것을 볼 수 있다.

public class Main {
    public static void main(String[] args) {
        System.out.println("프로그램 시작!");
        try { //예외가 생길 여지가 있는 구문을 넣어준다
            int result = 10/0;
                    //오류가생긴 타입 //e- 객체
        }catch (ArithmeticException e){//catch- 어떤 오류를 잡을 것인지 넣어준다
            //오류 처리코드
            System.out.println("오류가 발생했어요!");
        }
        System.out.println("프로그램 종료");
    }
}

try{
    //에러가 발생할 수 있는 코드
    throw new Exception(); //강제 에러 출력 
}catch (Exception e){
    //에러시 수행
     e.printStackTrace(); //오류 출력(방법은 여러가지)
     throw e; //최상위 클래스가 아니라면 무조건 던져주자
}finally{
    //무조건 수행
} 

에러가 났던 ArithmeticException을 사용하지 않고 Exception을 사용하는 이유는 상위 클래스임으로 모든 예외를 잡을 수 있기 때문이다



자바의 스레드 Thread

운영체제 Operating System

컴퓨터의 하드웨어를 사용하게 해주는 프로그램이다

프로세스 Process

현재 실행중인 프로그램. 각프로그램마다 메모리를 사용한다
프로그램을 실행시키기 위해 운영체제로부터 자원(resource)을 받아야 한다.

  • resource
    1. code: 프로그램 실행 코드
    2. data: 프로그램을 실행하기 위한 데이터
    3. heap : 동적 메모리영역
    4. stack : 메소드를 호출하기 위한 메모리 영역

    운영체제 입장에서 보면 자바의 JVM도 하나의 프로세스이다
    하나의 프로세스 안에서도 여러개의 흐름이 동작할 수 있다


스레드 Thread

  • 프로세스에는 최소한 한개 이상의 스레드(Thread)가 존재한다
    • 싱글스레드: 스레드 하나만 존재
      우리가 자바코드를 짜고 main에서 실행할때 사용했던것
    • 멀티스레드: 스레드 여러개
      적정량의 스레드를 유지해야함. resource 부족에 시달릴 수 있다


스레드 thread는 exception stack을 별도로 가지고 있는 실행 흐름이다
스레드는 독립적인 실행흐름이라서 스레드마다 스택이 별도로 할당이 된다

자바는 JVM만 있다면 어떤 운영체제에서도 동작할 수 있다. 자바 프로그램이 동시에 작업을 하도록 하기 위해서는 스레드를 공부해야만 한다!



프로세서 Processor

  • CPU안에 실제로 일을 할 수 있는 것을 코어cor라고 한다

    • 코어는 한순간에 하나의 일밖에 못한다 (일꾼인데 일 하나밖에 못함)

      • 시분할 기법: 싱글 코어라고 가정하였을때 여러프로그램이 마치 동시에 실행되는 것처럼 보이는 기법 (여러개의 프로그램을 조금씩 실행함) ⇒ 멀티테스킹 코어 하나가 시분할 기법을 사용하여 마치 동시에 여러개의 기능을 수행하는것처럼 보이게 하는게 멀티 테스킹이다
    • 멀티 프로세싱 Milti Processing: 프로그램 두개(코어 2개 이상)가 시간적의미로 동시에 실행하는것
      하나의 프로세스 안에서 여러개의 코어로 동시에 실행하는것

멀티테스킹 VS 멀티 프로세싱

  • 멀티 테스킹 Multi Tasking : 코어 하나로 굴리면서 마치 여러개의 기능을 수행하는 것처럼 보이게 하는것
  • 멀티 프로세싱 Multi Processing: 멀티 코어로 시간적인 의미로 동시에 실행하는것.


멀티 스레딩 Multi-Threading

  • 장점
    • 같은 리소스를 가지고 여러개의 일을 하기때문에 효율적인 사용이 가능하다
    • 프로그램을 사용하는 사람에게 응답속도를 높여준다
  • 단점
    • 프로그램이 어렵다 → 공유자원을 관리해야함 → 공유자원에 대한 동기화 처리를 해줘야 한다 ⇒ 잘못되면 데드락(교착상태): 끝나지않고 영원히 실행
    • 스레드 스케줄러에 의해서 제어가 되기 때문에 직접적인 제어가 까다롭다


자바에서 스레드(Thread) 만들기

자바에서 main() 메소드 자체가 스레드를 뜻하지 않는다

  • JVM이 스레드를 만들어서 스레드가 메인을 호출한다
  • 자바에서 스레드는 객체(인스턴스)다.
    인스턴스라는 의미는 이것을 만들어내는 클래스가 존재한다 ⇒ Thread class

방법1 - Thread 클래스 상속

스레드 클래스를 직접상속해서 Userdefine 사용자 정의 스레드 클래스를 만든다

  • 자바는 단일상속만 지원하기 때문에 (다중상속안됨)하나만 사용 가능한 제약이 있다
  • 클래스끼리의 결합이 강해져서 재사용하기가 힘들다
  • 직접적인 호출이 아닌 간접 호출이다
    t.start()와 밑의 println은 스케줄러에 의해 실행순서가 달라진다
class MyThread extends Thread{ 
@Override
    public void run() {
        System.out.println("Hello!");
    }
}
public class Main {
    public static void main(String[] args) {
        MyThread t = new MyThread();
        t.run(); //위의 클래스로부터 파생된 새로운 메소드 run() 실행
        t.start(); //thread를 생성하고 stack을 할당받고 run()호출한다 
    }
}

방법2 - Runnable 인터페이스 구현

Runnable Interface 스레드를 만들기 위한 용도의 인터페이스를 사용한다

  • Runnable 인터페이스를 받아 UserDefine 클래스를 생성하고 난뒤 객체(인스턴스)를 만든다
  • 상속관계가 없기 때문에 1번보다 자유롭다
  • 1번 처럼 상속 받는것보다 인터페이스로 구현하는것이 더 자주 사용된다
class MyThread extends Thread{ //방법1
@Override
    public void run() {
        System.out.println("Hello!");
    }
}
class MyThread2 implements Runnable{ //방법2
    @Override
    public void run() {
        System.out.println("실행이된다! ");
    }
}
public class Main {
    public static void main(String[] args) {
        MyThread t = new MyThread();
        t.run(); //위의 클래스로부터 파생된 새로운 메소드 run() 실행
        t.start(); //thread를 생성하고 stack을 할당받고 run()호출한다
        MyThread2 a = new MyThread2(); 
        Thread t1 = new Thread(a);
        t1.start();
        System.out.println("안녕하세요!");
    }
}
결과>>
Hello!
Hello!
안녕하세요!
실행이된다! 

1,2 방법 둘다 내가 스레드를 만들어야한다



코드 설명

  • 일반적인 run()은 스레드가 생성되지 않는다
  1. main스레드 스택이 최초생성되어main()이 스택에 쌓인다
  2. main 스택의 main메소드 영역에 t변수가 생성된다
    MyThread 인스턴스도 힙에 생성된다 (t 변수가 인스턴스 참조)
  3. t.run() 호출로 run() 스택이 main() 에 쌓인다 -> Hello출력
  • 새로운 thread가 생성되는 start()
  1. t.start()호출로 인해 새로운 Thread스레드가 생성된다. stack도 새롭게 할당됨. run()을 호출하여 Hello 출력
  2. main메소드 영역에 a변수 생성 MyThread2 인스턴스가 힙에 생기고 a가 인스턴스를 참조한다
  3. main메소드 영역에 t1 변수가 생성된다 Thread 인스턴스가 힙에 생성된다
    t1에 a가 생성자에 들어간다. a는 Thread 인스턴스를 참조할수 있게되었다.
  4. t1.start()로 인해 main 스택에 start()가 쌓인다. 새로운 Thread스레드 생성으로 stack도 할당되어 공간이 새롭게 생긴다. 여기서 run()메소드가 들어가 실행한다 -> 실행이된다 출력
  5. main()의 마지막 println이 안녕하세요를 출력하고 끝낸다
  • thread scheduler에 의해 실행되기 때문에 처음 run()을 제외한 나머지는 특정 thread내부의 method의 실행순서가 보장되지 않는다


Java Thread start() & run() 상태전이

  • new() : 아직실행이 되지 않은 상태 = 객체상태
  • start() : 실행이된다 (스레드의 상태가 runnable로 변경) = 대기상태
    CPU - 코어에 의해 선택이 가능한 상태이다
  • Thread Scheduler : JVM내부에 있는 ThreadScheduler가 runable 상태에 있는 여러개의 스레드중 선택해 run 상태로 바꾼다
  • Running (CPU를 점유하고 있는 상태 : 코어가 달라부터있음) = run() 수행
    • 메인스레드는 여기에 있다!
  • 일정량을 수행하고난뒤 다시 runnable 상태로 되돌린다
  • run() 상태가 끝나면 (메소드 호출이 끝나면) dead 상태로 빠진다
    • 이 객체는 재활용 할 수 없다 새객체 만들어서 해야함

예제

class ThreadEX_01_1 extends Thread{
    @Override
    public void run() {
        for(int i=0; i<5; i++){
            System.out.println(this.getName());
        }
    }
}
class ThreadEx_01_2 implements Runnable{
@Override
    public void run() {
        for(int i=0; i<5; i++){
            System.out.println(Thread.currentThread().getName());  //runabl로부터 구현한거지 아직 스레드가 아니다!
                                                            //현재 실행중인  스레드 실행
        }
    }
}
public class ThreadExam01 {
    public static void main(String[] args) {
        ThreadEX_01_1 t1 = new ThreadEX_01_1();
        ThreadEx_01_2 r = new ThreadEx_01_2();
        Thread t2 = new Thread(r);
        t1.start();
        t2.start();
        System.out.println("main thread 종료");
    }
}
  • 1번 실행 결과
  • 2번 실행 결과

    Thread 종료되는 결과가 계속 바뀌는 것을 볼 수 있음

  • start()를 수행하면 Thread가 생성(new)되고 Runnable상태로 들어간다. 스케줄러에 의해 선택을 받을 수 있는 상태이다. 생성된 다른 스레드들도 대기를 하고 있음. 스케줄러는 알고리즘에 의해 선택을 한다(우리는 알 수 없다)
  • Runnable에 있는 Thread를 스케줄러가 선택하면 CPU(Core)가 붙어 Running상태로 변경한다. (start()는 스레드 생성과 run()을 동시에 수행함) 열심히 일을하다 스케줄러가 다른 Thread를 선택하게되면 CPU가 떨어지고 다시 Runnable상태로 변경된다
  • 이렇게 왔다갔다 상태가 변경되다가 모든 작업이 끝나면 Dead 상태로 변경된다
    Dead로 바뀐 스레드는 다시 실행이 불가능하다 새로 스레드를 생성해야함

SingleCore 싱글코어 MultiCore멀티코어

  • Single Core 싱글 코어
    - 싱글 스레드 : 한번만 문맥교환을 하기 때문에 전체 작업속도가 빠르다
    - 멀티 스레드 : 여러번 문맥교환을 하기 때문에 전체 작업속도가 느리다
    하지만 동시에 일을 하는것처럼 멀티 테스킹이 가능하다
  • Multi Core 멀티 코어
    - 싱글 코어와 달리 일할 일꾼이 많은 멀티코어는 전체 작업속도가 빠르며 일이 동시에 진행될 수 있다. 하지만 공유자원에 대한 부분을 처리하기가 어렵다



Daemon Thread (괴물 thread)

  • 다른일의 스레드의 보조적인 작업을 위해 사용
  • Daemon thread는 이 스레드를 파생시킨 스레드가 종료되면 같이 종료된다
    메인스레드가 종료되면 같이 끝나버림

자바에서 deamon thread

  • 뒤쪽에서 일을하는애 → 가비지 컬렉터 Garbge collection
    • 메인이 종료되면 같이 종료되고 따로 실행할 필요가 없다
  • 자동저장 하는애 → 워드프로세서의 자동저장

어떻게 만들지?

  • 메소드를 만들면 됨 스레드.setDaemon(true);
  • 예제코드
public class ThreadExam2 implements Runnable
{
    static boolean autoSave = false;
    public static void main(String[] args) { //메인스레드는 이미 실행중!
        Thread t = new Thread(new ThreadExam2());
        t.setDaemon(true);
        t.start(); //t 스레드 실행
for (int i = 0; i < 10; i++) {
        try {
            Thread.sleep(1000); //메인 스레드를 1초 재운다
        } catch (Exception e) {
        }
        System.out.println(i);
        if(i==5) {
            autoSave = true; //데몬 실행
            }
        }
    }
    @Override
    public void run() {
        while (true){ //t 스레드는 계속 실행
            try {
                Thread.sleep(3000); //t 스레드는 3초동안 재움
            }catch ( InterruptedException e){
            }
            if (autoSave){ //3초마다 저장한다 
                System.out.println("자동저장되었어요!");
            }
        }
    }
}
출력>>
0
1
2
3
4
5
6
7
자동저장되었어요!
8
9
  1. 메인스레드와 t스레드를 생성했다
  2. mian스레드는 1초마다 자면서 i의 값을 찍는다
  3. t 스레드는 3초마다 자면서 실행되는 동안 i=5가 될때 autoSave로 자동저장을 실행한다


기억해야하는 Thread Method

앞서 start()를 배웠다 JAVA에는 다양한 스레드 메소드가 존재한다

  • sleep() : 일정시간동안 스레드를 중지시킨다
  • interrupt() : 스레드를 중지 (sleep을 깨우는(중지) 용도로도 사용)
  • yeid() : 스레드가 자신에게 주어진 수행시간을 다 쓰지 않고 다른 스레드에게 양보하는 방법

    sleep()yeid() 는 static 메소드이다
    스레드 자기 자신한테만 동작한다

    • sleep() : 남을 재울 수 없고 나만 스스로 잘수 있다
    • yeid() : 남에게 양보할 수 없고 나만 양보할 수 있다

sleep()

  • 일정시간동안 스레드를 중지시킨다
  • 지정된 시간이 다 되거나 Thread에 대해 interrupt()가 호출되면 exception이 뜬다. Interrupted Exception 발생하면서 sleep에서 깨어난다
  • 항상 try-catch를 사용해야한다

스레드가 깨어나는 방법

  1. 시간이 다 된다 (Sleep time out)
  2. interruped()로 깨어난다
  • 스레드가 한번 데드상태가 되면 끝남
  • sleep은 실행중에 일시정지 -outerwise blocked로 멈춘다
    • 시간이 timeout 되거나
    • 누군가에 의해서 interrupt되거나
  • otherwiseblocked후 sleep timeout을 가진뒤에 runnable이됨
    • 3초뒤 실행이라고 해도 언제 실행될지 모름
class ThreadExam03_1 extends Thread{
    @Override
    public void run() {
        try {
            Thread.sleep(2000); //현재실행하는 스레드를 재워라 => 메인스레드가 자는거
        }catch (Exception e){

        }for (int i=0; i<300; i++){
            System.out.print("-");
        }
        System.out.print("<<Thread 1 종료>>");
    }
}

class ThreadExam03_2 extends Thread{
    @Override
    public void run() {
        for (int i=0; i<300; i++){
            System.out.print("|");
        }
        System.out.print("<<Thread 2 종료>>");
    }
}
public class ThreadExam03 {
    public static void main(String[] args) {
        ThreadExam03_1 t1 = new ThreadExam03_1();
        ThreadExam03_2 t2 = new ThreadExam03_2();

        t1.start();
        t2.start();
    }
}

iterrupt()

Interrupt() : 스레드를 중지시킴

  • stop() → thread 강제중지 → 이제는 사용안함 (의도치않게 다른 결과를 냄)
  • start() → thread 시작! → interrupt()
    스레드 실행중에 작업이 끝나기전에 해당 스레드를 중지시키고 싶을 때 사용
    interrupt() 이용 → 직접 중지시키지 않는다
    스레드의 내부 상태값인 Interrupted state 를 변경해주는 역할
  • 스레드가 interrupt가 되었는지 확인하는 메서드
    • interrupted() : interrupte가 되었니? → thread의 static
      특정 스레드 지칭할수 없음.
      현재 실행중인 스레드가 interrupt가 걸렸는지 안되었는지 알 수 있다
      상태값을 조사하고 그 상태 값을 false로 바꾼다 (초기화 한다)
    • is_interrupted() : static이 아니다
      인스턴스 메서드라 특정 스레드를 지칭할수있다
      현재 상태값만 true/false로 리턴을 해준다

class ThreadEx_04 extends Thread{

    @Override
    public void run() {
        int i= 10;
        while (i != 0 && !isInterrupted() ){
            //i=0이면 튕겨나간다
            System.out.println(--i);

            try{
                Thread.sleep(3000); //제대로 실행되지 않는다 -> 계속 스레드가 돌아감
            }catch (Exception e){
                interrupt(); //그래서 한번더 재재를 해야한다
            }
           // for(long k=0; i<250000L; k++); //시간지연
        }
        System.out.println("카운트가 종료되었어요!");
    }
}
public class ThreadExam04 {
    public static void main(String[] args) {
        /**스레드 인스턴스 생성*/
        Thread t = new ThreadEx_04(); //내가 직접 만드는 인스턴스는 ThreadEX_04지만 타입은 상위타입 Thread
        t.start(); //동적바인딩으로 타입을 상위타입으로 사용한다

        //Swing에 있는 옵션펜 - 입력할수 있는 창이 생성된다 -> 입력값이 프로그래밍한테 전달된다
        //값을 입력할때까지 메인 스레드가 멈추게된다
        String input = JOptionPane.showInputDialog("값을 입력하세요");
                                    //메세지의 리턴타입으로 들어간다
        System.out.println("입력값은 :" + input);
        t.interrupt();
        //Thread t의 interrupted 상태가 true가 된다
        System.out.println("Thread의 상태값은 :" + t.isInterrupted());
    }
}

yeid()

  • Thread가 자신에게 주어진 수행시간을 다 쓰지 않고 다른 Thread에게 양보하는 방법
    ex) 0.5는 쉬고 0.5는 할꺼야 → 그사이에 스레드를 양보하는 방법
  • 프로그램의 응답성을 높이기 위해 사용한다

class ThreadEx_06 implements Runnable{
        //멀티코어 환경에서 캐시가 아닌 메인 메모리에서 값을 불러오겠다는게 volatile이다
    volatile boolean suspended = false;  //일시정지 되었니?
    volatile boolean stopped = false; //중지되었니?

    @Override
    public void run() {
        //위의 변수 2개를 이용해서
        //멈추지 않으면 계속 돌아라
        while(!stopped){
            //일시멈춤이 아니라면
            if (!suspended){      //실행중인 스레드 호출
                System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            }catch (Exception e) {

            }
            }else {
                Thread.yield();
            }
        }
    }

    public void suspend(){
        suspended = true;
    }

    public void stop(){
        //stop이 호출되면 true가 떠서 while문이 멈추게된다
        stopped = true;
    }
    public void resume(){
        suspended = false; //일시정리된것을 다시 실행시킨다
    }

}
public class ThreadExam06 {
    public static void main(String[] args) {
        ThreadEx_06 r1 = new ThreadEx_06(); //runnable 3개
        ThreadEx_06 r2 = new ThreadEx_06();
        ThreadEx_06 r3 = new ThreadEx_06();
        Thread t1 = new Thread(r1, "*"); //thread 3개
        Thread t2 = new Thread(r2, "**");
        Thread t3 = new Thread(r3, "***"); //동일한 작업을 하는 스레드를 3개 생성

        t1.start();
        t2.start();
        t3.start();  //runnable이 스케줄러에 의해 랜덤으로 스레드를 선택해서 작동시킨다

        try {
            Thread.sleep(2000); //메인 스레드를 재운다
            r1.suspend(); //t1을 일시 중지
            Thread.sleep(2000);
            r2.suspend(); //t2을 일시 중지
            Thread.sleep(2000);
            r1.resume(); //t1이 다시 동작하도록 설정
            r1.stop();
            r2.stop();
            Thread.sleep(2000);
            r3.stop();
        }catch (Exception e){

        }
    }
}

Join()

다른 스레드를 지정해서 나를 멈추고 참여시킨다
(현재 실행중인 스레드가 멈추고 특정 스레드를 끌어들여 수행하도록 한다)

  • Join() : 시간을 정해주지 않고 스레드 스케줄러에 의해 결정하게됨
  • Join(long 초): 시간을 정해서 실행되게함
  • join 예제
class ThreadEx_07_1 extends Thread{
    @Override
    public void run() {
        for (int i=0; i<300; i++){
            System.out.print("-");
        }
    }
}
class ThreadEx_07_2 extends Thread{
    @Override
    public void run() {
        for (int i=0; i<300; i++){
            System.out.print("|");
        }
    }

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

        //두개의 스레드 생성
        Thread t1 = new ThreadEx_07_1();
        Thread t2 = new ThreadEx_07_2();

        //둘다 runnable 상태로 넣는다
        //스케줄러가 내부적인 메커니즘으로 선택을 하여 실행시킨다 -> 누가 될지 모름
        //스레드 큐에 들어가 튕겨나옴 우리는 알수 없다
        t1.start();
        t2.start();

        //main, t1, t2 3개가 돌고있는 상황
        try {
            //main스레드가 멈추고 t1을 참여시킨다
            t1.join();
            //main스레드가 제일 뒤로 밀린다
            t2.join();
        }catch (Exception e){
        }
        //위의 명령문이 아니었다면 main이 제일먼저 끝났을 것이다
        //join이 들어가면서 t1, t2가 먼저 수행
        System.out.println("<<main 종료>>");

    }
}

  • sleep은 static 메소드이다
    특정 스레드를 지정해서 재울 수 없다
  • join은 인스턴스 메소드이다
    특정 스레드를 지정이 가능하다

  • join 을 언제 사용하면 좋을까?
//편하게 만들기 위해
class ThreadEx08_1 extends Thread{
    //static: 인스턴스 안만들어도됨 -> final: 재할당안됨
    //메모리의 총량은 1000이다
    final static int MAX_MEMORY = 1000; //상수는 전부 대문자화 + SnakeCase 사용
    //실제로 사용하는 메모리(변수)
    int usedMemory = 0;

    @Override
    public void run() {
        //무한루프
        while(true){
            //sleep을 사용하려면 try-catch가 강제됨
            try {
                //thread 클래스가 가지는 static 메소드
                Thread.sleep(10000); //10초동안 자라
            }catch (Exception e){
                System.out.println("interrupt()에 의해서 깨어남");
            }
            gc();
            System.out.println("메모리 청소 완료! 현재 사용가능한 메모리 량은 : "
                    + freeMemory());
        }
    }
    //내부에서만 사용하는 메소드임으로 원래 private가 맞다
    //garbge collector을 사용 10초마다 청소해준다
    public void gc(){
        usedMemory -= 300;
        if (usedMemory < 0){
            //사용중인 메모리양을 마이너스가 되지 않도록 조치
            usedMemory = 0;
        }
    }

    //프로그램에서 사용하는 전체 메모리량을 리턴
    public int totalMemory(){
        return MAX_MEMORY;
    }

    //남은 용량 (사용가능한 메모리량)을 리턴
    public int freeMemory(){
        return MAX_MEMORY - usedMemory;
    }

}
public class ThreadExam08 {
    public static void main(String[] args) {
        ThreadEx08_1 t = new ThreadEx08_1();
        t.setDaemon(true);
        t.start();

       int requiredMemory = 0;
       for(int i=0; i<20; i++){
           requiredMemory = (int)(Math.random() * 10)*20;
                            //0보다 크고 200보다 작은 정수

           //필요한 memory가 사용할 수 있는 양보다 크거나
           //현재 전체 메모리양의 60% 이상을 사용하고 있을때 gc를 실행
           //if - 지금 내가 필요한 메모리가 가용메모리보다 큰 경우
           if ((requiredMemory > t.freeMemory()) ||
                   (t.freeMemory() < t.totalMemory() * 0.4)){
               t.interrupt(); /**gc()실행이 끝날때까지 기다리지 않는다*/
               //join을 건다 - gc가 main보다 먼저 수행되도록 하기 위해서
               try{
                   t.join(100);
               }catch (Exception e){

               }
           }
           //현재 사용하는 메모리에 위쪽에서 사용하려는 메모리양을 추가
           t.usedMemory += requiredMemory;
           System.out.println("현재 사용된 메모리 량: " + t.usedMemory);

           //전체 메모리량은 1000인데 main이 random 하게 계속 사용함
           //if에서 가비지가 청소를 한다 (이미 60%사용하거나 사용하려는 메모리량보다 가용메모리가 적을때)
       }
    }

}

업로드중..



참고자료
https://coco-log.tistory.com/31
https://coding-factory.tistory.com/280
https://kim-jong-hyun.tistory.com/101
https://veneas.tistory.com/entry/Java-%EC%9E%90%EB%B0%94-Thread-%EC%A3%BC%EC%9A%94-%EA%B8%B0%EB%8A%A5sleep-interrupt-join

profile
개발기록

0개의 댓글