쓰레드와 동기화(1)
1.프로세스와 쓰레드(process & thread)
- 프로세스는 실행중인 프로그램을 의미한다.
- 쓰레드는 프로세스 내에서 별도의 실행흐름을 갖는 대상이다.
- 프로세스 내에서 둘 이상의 쓰레드를 생성하는 것이 가능하다.
- 사실 쓰레드는 모든 일의 기본 단위이다. main 메소드를 호출하는 것도 프로세스 생성시 함께 생성
되는 main 쓰레드를 통해서 이뤄진다.
- 별도의 쓰레드 생성을 위해서는 별도의 쓰레드 클래스를 정의해야 한다.
- 쓰레드 클래스는 Thread를 상속하는 클래스를 의미한다.
- start 메소드가 호출되면 쓰레드가 생성되고, 생성된 쓰레드는 run 메소드를 호출한다.
class ShowThread extends Thread //쓰레드를 상속 받아야 한다.
{
String threadName;
public ShowThread(String name)
{
threadName=name;
}
public void run() // start 메소드가 호출되면 실행된다.
{
for(int i=0; i<100; i++)
{
System.out.println("안녕하세요. "+threadName+"입니다.");
try
{
sleep(100); //1/1000 초 단위로 실행흐름을 일시적으로 멈춘다.
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
}
}
class ThreadUnderstand
{
public static void main(String[] args)
{
ShowThread st1=new ShowThread("멋진 쓰레드");
ShowThread st2=new ShowThread("예쁜 쓰레드");
st1.start(); //쓰레드 실행
st2.start();
}
}
2.쓰레드를 생성하는 두 번째 방법
- Runnable 인터페이스를 구현하는 클래스의 인스턴스를 대상으로 Thread 클래스의 인스턴스를 생성한
다. 이 방법은 상속할 클래스가 존재할 때 유용하게 사용된다.
class [클래스이름] extends Sum implements Runnable
- 상속받을 클래스가 있을 경우 Runnable 인터페이스를 구현하여 쓰래드 클래스를 만든다.
- join 메소드가 호출되면, 해당 쓰레드의 종료를 기다리게 된다.
AdderThread at1=new AdderThread(1, 500);
tr1.join();AdderThread at1=new AdderThread(1, 500);
AdderThread at2=new AdderThread(501, 1000);
Thread tr1=new Thread(at1);
Thread tr2=new Thread(at2);
tr1.start();
tr2.start();
try
{
tr1.join(); //join 메소드가 호출되면 해당 쓰레드가 종료될때까지 대기한다.
tr2.join();
}
catch(InterruptedException e)
{
e.printStackTrace();
}
- 위 예제에서 main 쓰레드가 join 메소드를 호출하지 않았다면, 추가로 생성된 두 쓰레드가 작업을
완료하기 전에 값을 참조하여 쓰레기 값이 출력될 수 있다.
3.쓰레드의 특성
1) 쓰레드의 스케줄링과 우선순위 컨트롤
- 우선순위가 높은 쓰레드의 실행을 우선시한다.
- 우선순위가 동일할 때는 CPU의 할당시간을 나눈다.
- 메소드 getPriority의 반환 값을 통해서 쓰레드의 우선순위를 확인할 수 있다.
- 아래의 실행결과에서 보이듯이, 우선순위와 관련해서 별도의 지시를 하지 않으면, 동일한 우선순위
의 쓰레드들이 생성된다.
2) 낮은 우선순위의 쓰레드 실행
- 쓰레드가 CPU의 할당을 필요로 하지 않을 경우, CPU를 다른 쓰레드에게 양보한다.
3) 쓰레드의 라이프 사이클

Runnable 상태의 쓰레드만이 스케줄러에 의해 스케줄링 가능하다.
- 그리고 앞서보인 sleep, join 메소드의 호출로 인해서 쓰레드는 Blocked 상태가 된다.
- 한번 종료된 쓰레드는 다시 Runnable 상태가 될 수 없지만, Blocked 상태의 쓰레드는 조건이 성립되면 다시 Runnable 상태가 된다.
4) 쓰레드의 메모리 구성

- 모든 쓰레드는 스택을 제외한 메소드 영역과 힙을 공유한다. 따라서 이 두 영역을 통해서 데이터를 주고 받을 수 있다.
- 스택은 쓰레드 별로 독립적일 수 밖에 없는 이유는, 쓰레드의 실행이 메소드의 호출을 통해서 이뤄지고, 메소드의 호출을 위해서 사용되는 메모리 공간이 스택이기 때문이다.