스레드란?

병렬작업(multi-tasking)은 여러 개의 작업을 동시에 실행시켜서 컴퓨터 시스템의 성능을 높이기 위한 기법이다.

다중 스레딩(multi-threading)은 이 병렬 작업의 아이디어를 프로그램 안으로 가져온 것, 즉 하나의 프로그램이 동시에 여러 가지 작업을 할 수 있다. 

이들작업을 스레드(thread)라고 부른다.


|프로세스와 스레드

프로세스는 자신만의 데이터를 가지는 데 반하여 스레드들은 동일한 데이터를 공유한다.(스레드는 하나의 프로세스 안에 존재)

프로세스 : 독자적으로 실행이 가능한 환경, 프로그램이 실행되면 프로세스가 된다.

스레드 : 경량 프로세스라고도 불림, 스레드들은 프로세서 안에서 존재, 메모리와 파일을 포함하여 프로세스의 모든 자원을 공유한다.

      모든 자바 프로그램은 적어도 하나의 스레드를 가지고있다. 즉 main( ) 스레드라고 부르는 하나의 스레드로 출발.


스레드 생성과 실행

스레드를 만드는 방법에는 다음의 두 가지가 있다.

1. Thread 클래스를 상속하는 방

2. Runnable 인터페이스를 구현하는 방법


Thread 클래스

Thread( ) : 매개 변수가 없는 기본 생성자

Thread(String name) : 이름이 name인 Thread 객체를 생성

Thread(Runnable target, String name) : Runnable을 구현하는 객체로부터 스레드를 생성

static int activeCount( ) : 현재 활동 중인 스레드의 개수를 반환

String getName( ) : 스레드의 이름을 반환

int getPriority( ) : 스레드의 우선 순위를 반환

void interrupt( ) : 현재의 스레드를 중단한다.

boolean isInterrupted( ) : 현재의 스레드가 중단될 수 있는지를 검사

void setPriority(int priority) : 스레드의 우선 순위를 지정

void setName(String name) : 스레드의 이름을 지정

static void sleep(int milliseconds) : 현재의 스레드를 지정된 시간만큼 재운다.

void run( ) : 스레드가 시작될 때 이 메소드가 호출

void start( ) : 스레드를 시작

static void yield( ) : 현재 스레드를 다른 스레드에 양보


Thread 클래스를 상속하기

class Counting extends Thread{

public void run(){

for(int i=0;i<10;i++)

{

System.out.println(i);

}

}

}

-> Thread 클래스를 상속받아 서브 클래스를 만들고 run( ) 메소드를 오버라이드하는 방법. run( ) 메소드에 스레드가 수행하여야 할 작업 내용이 들어감. 이 서브 클래스의 인스턴스를 생성하고 start( ) 메소드를 호출하면 스레드가 실행

public class Test{

public static void main(String args[ ]){

Thread t = new Counting();

t.start();

}

}


|Runnable 인터페이스를 구현하는 방법( 추천 )

Thread 클래스를 확장하는 방법은 하나의 큰 단점이 존재, 자바에서는 단일 상속만이 가능하므로 다른 클래스를 이미 상속한 클래스는 스레드로 만들 수 없다. 따라서 Runnabel 인터페이스를 구현.

1. Runnable을 구현하는 클래스를 생성

2. Runnable 클래스에 run( ) 메소드를 작성

3. Thread 클래스의 객체를 생성, Runnable 객체를 Thread 생성자의 매개 변수로 넘김

4. Thread객체의 start( ) 메소드를 호출


< 1, 2에 따라 Runnable을 구현하는 클래스를 작성>

class Counting implements Runnable{

public void main( )

{

for(int i =0;i<10;i++)

{

System.out.println(i);

}

}

}

<3, 4에 따라 Counting의 객체를 만들고 Thread 클래스의 객체도 생성>

public class Test{

public static void main(String args[ ] ){

Counting c = new Counting( );

Tread t = new Tread( c );

t,start( );

}

}


<예제-1>

0부터 9까지 세는 스레드 두 개 만들기!

 

출력결과


<예제-2>

경마 게임 : 난수를 매개 변수로 하여 sleep( )을 호출하는 스레드를 여러 개 작성. sleep( ) 메소드는 지정도니 시간 동안 현재 스레드의 실행을 중단.

출력결과


스레드 상태


스레드의 스케줄링

스케줄링 : 어떤 순서로 스레드를 수행시킬 것인가를 결정( 자바 런타임 시스템은 우선 순위 스케줄링을 이용 , 만일 같은 우선 순위를 가진 스레드들이 있다면 이들은 라운드로빈 방식(스레드 각각에게 균등하게 CPU 시간을 분배하는 것)으로 수행 )

자바의 스케줄링 방식은 선점 형식( 더 높은 우선 순위를 가지는 스레드가 들어오면 수행되고 있는 스레드를 강제로 중단시키고 새로운 스레드를 수행)


|스레드의 우선순위

스레드는 생성될 때 자신을 생성한 스레드로부터 우선 순위를 상속 받음.


|sleep( )

현재 스레드의 실행을 지정된 시간 동안 중단( CPU의 시간을 다른 스레드에게 양보하는 효과적인 수단 )

 <1초 간격으로 메시지를 출력>

출력결과



|인터럽트

스레드로 하여금 현재 실행하고 있는 것을 멈추고 다른 것을 하도록함( 스레드가 수시로 인터럽트 검사를 하는 메소드를 호출하여야 한다)

<sleep()상태에서 인터럽트를 검사>


|조인

join( ) 메소드는 하나의 스레드가 다른 스레드의 종료를 기다리게 하는 메소드.( t가 현재 실행 중인 스레드 객체이면 다음 문장은 t가 끝날 때까지 현재의 스레드의 실행을 중단)

ex) t.join( );


동기화

한 번에 하나의 스레드만이 공유 데이터를 접근할 수 있도록 제어하는 방법

<동기화 문제 예시 - 저금,인출>

-> 하나의 은행 계좌를 생성하고 두 개의 스레드에게 매개 변수로 넘긴다. 상식적으로는 저금이 먼저 이루어지기 때문에 절대 마이너스가 될 수 없다. 그러나 실제 결과를 돌리면 "오류발생"을 출력하게 된다.


|동기화 문제의 이유

동시에 실행되는 스레드 사이에 있는 공유되는 데이터( 공유되는 데이터를 조작하는 코드를 임계 영역), 즉 임계영역에는 항상 하나의 스레드만이 존재하여야 한다.


|동기화된 메소드 이용

synchronized 키워드를 사용하면 어떤 한 순간에는 하나의 스레드만이 임계 영역 안에서 실행하는 것이 보장



스레드간의 조정

ex) 소비자 객체는 생산가자 데이터를 배달하기 전에 데이터를 가져오려고 시도하면 안된다. 또한 생산자도 소비자가 아직 이전 데이터를 가져가지 않았는데 새로운 데이터를 생산하면 안된다.

<생산자 소비자 문제>

출력결과

-> 생산자 스레드가 더 빠른 경우 이전에 생산된 케익을 소비자 스레드가 가져가기 전에 덮어쓰거나/ 소비자 스레드가 더 빠른 경우 똑같으 케익을 두 번 가져가는 경우가 발행


해결방법

1.동기화된 메소드를 사용하여 두 개의 스레드가 동시에 버퍼 객체에 접근하는 것을 막는다.

2.wait(), notify()메소드를 이용하여 명시적으로 알린다.


|wait( )와 notify( )를 사용하는 방법





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

7. 입출력 - 문자스트림  (2) 2016.06.09
6. 입출력-바이트스트림  (0) 2016.06.08
4. 예외처리  (0) 2016.06.08
3. Collections클래스  (0) 2016.06.08
2. 컬렉션  (0) 2016.06.07

+ Recent posts