java day13
멀티스레드 | 동기화 | 스케줄링 | 람다표현식 |
멀티스레드
운영체제에서는 실행중인 하나의 래플리케이션을 프로세스라고 부름. 사용자가 애플리케이션을 실행하면 운영체제로부터 실행에 필요한 메모리를 할당받아 애플리케이션의 코드를 실행하는것이 프로세스임.
스레드는 하나의 프로세스 내부에서 독립적으로 실행되는 작업단위로 운영체제에 의해 관리되는 하나의 작업 혹은 Task를 의미함. 다중 스레드 작업시에는 각 스레드간 정보를 주고 받을 수 있어 처리 과정의 오류를 줄일 수 있음. 단, 프로세스간에는 정보를 주고 받을 수 없음.
JVM에 의해 하나의 프로세스가 발생하고 main() 안에 실행문들이 하나의 스레드 발생함. main() 외에 또다른 스레드를 만들려면 Thread 클래스 상속하거나 Runnable 인터페이스를 구현함.
멀티스레딩는 여러 스레드를 동시에 실행시키는 응용프로그램을 작성하는 기법으로 메모리 공유로 인한 시스템 자원 소모가 줄고 동시에 두가지 이상의 활용이 가능하나 서로 자원을 소모하다가 충돌이 일어날 가능성이 있고 코드가 난해해질 가능성이 있음.
✔ 스레드 클래스는 start() 실행시 run() 메소드가 수행되도록 내부적으로 처리
스레드 생성 방법1 (Thread 클래스 상속)
public class 클래스명 extends Thread{
public void run(){
스레드 객체가 start() 호출하면 실행될 문장;
...
}
}
자료형 참조변수 = new 클래스명();
참조변수.start();
public class Thread1 extends Thread{
@Override
public void run() {
System.out.println("th1 Thread가 동작하고 있어요");
}
public static void main(String[] args) {
Thread1 th1 = new Thread1();
th1.start(); // 호출시 run() 실행
}
}
실행결과
th1 Thread가 동작하고 있어요
스레드 생성 방법2 (Runnable 인터페이스를 구현)
public class 클래스명 implements Runnable{
public void run(){
스레드 객체가 start() 호출하면 실행될 문장;
...
}
}
Runnable 참조변수1 = new 클래스명();
Thread 참조변수2 = new Thread(참조변수1);
참조변수2. start();
class TestRunnable implements Runnable{
@Override
public void run() {
System.out.println("스레드 동작중 ...");
}
}
public class Main3 {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + " start!");
Runnable r = new TestRunnable();
Thread th1 = new Thread(r);
th1.start();
try {
th1.join();
// th1가 끝날때 까지 main 스레드가 종료되지않음
}catch (Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " end!");
}
}
실행결과
main start!
스레드 동작중 ...
main end!
동기화
멀티 스레드 프로세스에서는 다른 스레드의 작업에 영향을 미칠 수 있기 때문에, 진행중인 작업이 다른 스레드에 간섭을 받지 않게 하려고 동기화가 필요함. 동기화를 하려면 간섭받지 않아야 하는 문장 또는 메소드를 락을 걸어 단 하나의 스레드만 출입이 가능.
멀티 스레드 프로그램에서 단 하나의 스레드만 실행 할 수 있는 코드 영역을 임계영역이라고함. 자바는 임계영역을 지정하기 위해 동기화 메소드를 제공함. 스레드가 객체 내부의 동기화 메소드를 실행하면 즉시 객체에 잠금을 걸어 다른 스레드가 동기화 메소드를 실행 하지 못하도록 함. 동기화 메소드를 만들기 위해서는 메소드 선언에 synchronized 키워드를 붙이면됨.
메소드 public synchronized 반환형 메소드명(매개변수1, ...){
}
문장 synchronized (this) {
}
스레드 스케줄링
스레드 객체를 생성하고 start() 메소드를 호출하면 바로 실행되는 것이 아니라 실행대기 상태가 됨. 실행 대기 상태는 언데든지 실행할 준비가 되어 있는 상태를 의미함. 운영체제는 실행 대기 상태에 있는 스레드 중에서 하나를 선택해 실행 상태로 만듬.
실행 상태의 스레드는 run() 메소드를 모두 실행하기 전에 다시 실행 대기 상태로 돌아갈 수 있으며, 실행 대기 상태에 있는 다른 스레드가 선택되어 실행 상태가 되기도함. 실행 상태에서 run()메소드의 내용이 모두 실행되면 스래드의 실행이 멈추고 종료상태가 됨.
스레드 객체 생성(NEW) -------start()------> 실행대기(Runnable)
| ^
일시정지상태(Blocked) | (반복) |
v |
종료(TERMINATED) <---------------------- 실행(Running)
run() 종료 run()
스레드 상태 제어
interrupt() : 일시정지상태의 스레드에서 InterruptedException을 발생시켜, 예외처리코드에서 실행 대기상태로 가거나 종료상태로 갈 수 있도록해줌.
sleep() : 주어진 시간 동안 스레드를 일시 정지 상태로 만듬. 주어진 시간이 지나면 자동적으로 실행 대기 상태가 됨.
stop() : 스레드가 즉시 종료됨. 불안전한 종료를 유발하므로 사용하지 않는 것이 좋음.
번외
람다 표현식
public class Calc{
public int func1(x,y){
int result = x < y ? x : y;
return result;
}
}
Calc calc =(x, y) -> x < y ? x : y; // 람다표현식
public class Lambda1 {
public static void main(String[] args) {
Calc minNum = (x, y) -> x < y ? x : y;
System.out.println(minNum.min(5,3));
}
}
public interface Calc {
public int min(int x,int y);
}
실행결과
3