<CS 지식> Java Thread

Google 아니고 Joogle·2022년 8월 2일
0

CS 지식

목록 보기
15/22

Process, Thread 참고

Thread in Java

자바에서 Thread를 구현하는 방법은 2가지가 있다
1. Runnable interface 구현
2. Thread 클래스 상속

implements Runnable

  • Runnable 인터페이스를 구현하는 경우에는 해당 클래스를 인스턴스화해서 Thread 생성자에 argument로 넘겨주어야 함
  • run()을 호출하면 Runnable 인터페이스에서 구현한 run()이 호출되므로 따로 오버라이딩 하지 않아도 되는 장점이 있음
public class ConsumerRunnable implements Runnable{

	int num;
	public ConsumerRunnable(int num) {
		this.num=num;
	}
	
	@Override
	public void run () {
		System.out.println("#"+num+" start");
		for (int i=0; i<1000; i++) {
			System.out.println("#"+num+" : "+i);
		}
		System.out.println("#"+num+" end");
	}

}

=> Thread c3=new Thread(new ConsumerRunnable(3)); 
		c3.start();

extends thread

  • Thread클래스를 상속받은 경우는, 상속받은 클래스 자체를 스레드로 사용할 수 있음
  • Thread 클래스를 상속받으면 스레드 클래스의 메소드 (getName())을 바로 사용할 수 있지만, Runnable 구현의 경우 Thread 클래스의 static 메소드인 currentThread()를 호출하여 현재 스레드에 대한 참조를 얻어와야만 호출이 가능

<currentThread ().getName() 사용>

public class ThreadTest implements Runnable {
    public ThreadTest() {}
    
    public ThreadTest(String name){
        Thread t = new Thread(this, name);
        t.start();
    }
    
    @Override
    public void run() {
        for(int i = 0; i <= 50; i++) {
            System.out.print(i + ":" + Thread.currentThread().getName() + " ");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Thread 구현


public class ConsumerThread extends Thread{
	int num;
	public ConsumerThread(int num) {
		this.num=num;
	}
	
	@Override =====> run을 override
	public void run () {
		System.out.println("#"+num+" start");
		for (int i=0; i<1000; i++) {
			System.out.println("#"+num+" : "+i);
		}
		System.out.println("#"+num+" end");
	}

}

스레드 실행

스레드 실행은 run()이 아닌 start()로 호출

  • Java의 call stack -> 실질적인 명령어들을 담고 있는 메모리로 하나씩 거내서 실행시키는 역할 (만약 동시에 두 가지 작업을 한다면, 두 개 이상의 콜 스택이 필요함)
  • 스레드를 이용한다는 건, JVM이 다수의 콜 스택을 번갈아가며 일처리를 하고 사용자는 동시에 작업하는 것처럼 보여줌
  • run() 메소드를 이용한다는 것은 main()의 콜스택 하나만을 이용하는 것으로 스레드의 활용이 아님 -> start() 메소드를 호출하여 JVM이 스레드를 위한 콜스택을 새로 만들고, context switching 동작

동기화

여러 스레드가 같은 프로세스 내의 자원을 공유하면서 작업할 때 서로의 작업이 다른 작업에 영향을 주기 때문에 동기화 필수적

Synchronized 활용

  • 서로 다른 두 객체가 동기화를 하지 않은 메소드를 같이 오버라이딩해서 이용하면, 두 스레드가 동시에 진행되므로 원하는 출력 값을 얻지 못함
  • 오버라이딩 되는 부모 클래스의 메소드에 synchronized 키워드로 임계영역을 설정
public synchronized void saveMoney(int save){    // 입금
    int m = money;
    try{
        Thread.sleep(2000);    // 지연시간 2초
    } catch (Exception e){

    }
    money = m + save;
    System.out.println("입금 처리");

}

public synchronized void minusMoney(int minus){    // 출금
    int m = money;
    try{
        Thread.sleep(3000);    // 지연시간 3초
    } catch (Exception e){

    }
    money = m - minus;
    System.out.println("출금 완료");
}

Sleep사용 -> Running 상태에서 Runnable 상태로

wait() & notify()

  • 스레드가 서로 협력관계일 경우, 무작정 대기시키는 것으로 올바르게 실행되지 않기 때문에 사용
  • Synchronized 블록 내에서 실행이 되어야 함
  • wait () : 스레드가 lock을 가지고 있으면 lock 권한을 반납하고 대기하게 만듦
  • notify () : 대기 상태인 스레드에게 다시 lock 권한을 부여하고 수행하게 만듦
  • notifyAll () : 잠들어있던 스레드 모두를 깨움

Reference
https://gyoogle.dev/blog/computer-language/Java/Thread.html

profile
Backend 개발자 지망생

0개의 댓글