nueijeel

[Java 이론] 0504 스레드와 동기화 본문

Java

[Java 이론] 0504 스레드와 동기화

nueijeel 2023. 5. 5. 00:27

2023.05.04

 

1. 스레드 (Thread)

 

동기

: 작업을 순차적으로 처리하는 것

 

비동기

: 동시에 여러 작업을 처리하는 것

 

스레드(Thread) 

: 비동기 처리를 위해 java에서 제공하는 클래스로 한 프로그램에 여러 개의 스레드를 동시에 동작시킬 수 있다.

오류 발생 가능성이 높은 작업을 별도의 스레드로 운영하면 안정적으로 운영할 수 있다.

Thread 클래스는 java.lang 패키지에서 제공하는 라이브러리 클래스이므로 별다른 import가 필요하지 않다.

 

 

< Thread 클래스의 생성자 >

//Thread 클래스는 4개의 생성자 가짐
Thread()
Thread(String s)
Thread(Runnable r)
Thread(Runnable r, String s)

//r : Runnable 인터페이스 객체
//s : Thread 식별자

 

< Thread 클래스의 주요 메서드 >

static void sleep(long msec)
throws InterruptedException
msec에 지정된 밀리초 동안 대기
void start() 스레드를 시작시킨다. run() 메소드를 호출
final int getPriority() 스레드의 우선순위를 반환
final void setPriority(int p) 스레드의 우선순위를 p로 설정
void run() 스레드가 실행할 부분을 기술하는 메소드로 하위클래스에서 오버라이딩해야한다.

 

 

 

 

- 스레드 생성 방법

 

1. Thread 클래스를 상속받는 클래스를 사용한다.

public MainClass{
	public static void main(String[] args){
    	TestClass1 t1 = new TestClass();	//스레드 객체 생성
        t1.start();				//스레드 수행
    }
}

class TestClass1 extends Thread{
	public void run(){	//오버라이딩
    	System.out.println("TestClass1");
    }
}

TestClass1 클래스는 Thread 클래스를 상속받아 run() 메서드를 오버라이딩 한다.

run() 메서드는 스레드를 시작시키는 start() 메서드에 의해 자동적으로 수행되는 메서드로, 프로그램에서 명시하지 않고도 자동적으로 호출된다.

start() 메서드는 스레드를 실행 가능 상태로 만들고, JVM이 CPU 할당이 가능 할 때 run() 메서드를 호출하면 스레드가 실행된다.

 

TestClass1 클래스의 스레드 객체 t1을 생성하고 start() 메서드를 호출해 스레드를 시작시킨다.

 

 

2. 스레드 기능을 제공하는 Runnable 인터페이스를 구현한다.

public MainClass{
	public static void main(String[] args){
        TestClass2 t2 = new TestClass2();
        Thread thread = new Thread(t2);
        thread.start();
    }
}

class TestClass2 implements Runnable{
	public void run(){
    	System.out.println("TestClass2");
    }
}

스레드 특성을 가져야 하는 클래스가 이미 다른 클래스의 상속을 받고있을 때 Runnable 인터페이스를 구현한다.

TestClass2 클래스도 Runnable 인터페이스의 run() 메서드를 오버라이딩한다.

 

TestClass2 클래스의 객체 t2를 생성하고 이를 매개변수로 하여 Thread 클래스로부터 객체를 생성한다(Thread 생성자 3번째 유형). 생성된 스레드 객체로 스레드를 시작시킨다.

 

 

 

 

- 스레드 우선순위

 

스레드에 우선순위를 부여하여 우선순위가 높은 스레드가 우선적으로 실행되게 할 수 있다. 무조건 우선순위가 높은 스레드가 먼저 전부 수행되는 것이 아니고 대체적으로 우선 수행되는 것이다. 우선순위는 1~10의 범위로 기본 값은 5이고, 10이 우선순위가 가장 높은 값이다. JVM은 모든 스레드가 같은 우선순위를 가질 경우 일정 시간동안 스레드를 번갈아가며 수행한다.

 

public class MainClass {
	public static void main(String[] args) {
		Thread1 t1 = new Thread1();
		Thread2 t2 = new Thread2();
		Thread3 t3 = new Thread3(); //스레드 객체 생성
		
        	t1.setPriority(10);
        	t2.setPriority(1);
       		t3.setPriority(1);	//스레드 우선순위 부여
        
        	t1.start();
        	t2.start();
        	t3.start();	//스레드 시작
	}
}

class Thread1 extends Thread{
	@Override
    public void run() {
        for(int i = 0 ; i < 10 ; i++) {
            System.out.println("Thread1");
        }
    }
}
class Thread2 extends Thread{
	@Override
    public void run() {
        for(int i = 0 ; i < 10 ; i++) {
            System.out.println("Thread2");
        }
    }
}
class Thread3 extends Thread{
	@Override
    public void run() {
        for(int i = 0 ; i < 10 ; i++) {
            System.out.println("Thread3");
        }
    }
}

 

 

- 스레드 동기화

 

임계영역

: 다수의 스레드가 동시에 접근 가능하지만, 한 순간에는 하나의 스레드만 사용할 수 있는 영역.

비동기처리로 임계영역에 접근할 경우 오류가 발생할 수도 있는데 동기화를 통해 이를 방지할 수 있다.

 

 

자바는 임계영역 지정을 위한 synchronized 메소드를 제공한다. 해당 메소드를 통해 다수의 스레드가 각자 순서를 가지고 대기와 수행을 반복한다.

 

public MainClass{
	public static void main(String[] args){
    		Thread1 t1 = new Thread1();
        	Thread2 t2 = new Thread2();
        	Thread2 t3 = new Thread3();
        
        	t1.start();
        	t2.start();
        	t3.start();
    	}
}

class Thread1 extends Thread{
	public void run(){
    		TestClass1.testMethod("Thread1");
    	}	
}
class Thread2 extends Thread{
	public void run(){
    		TestClass1.testMethod("Thread2");
    	}	
}
class Thread3 extends Thread{
	public void run(){
    		TestClass1.testMethod("Thread3");
    	}	
}
class TestClass{
	public synchronized static void testMethod(String name){
    		for(int i = 0; i < 10; i ++){
        		System.out.printf("%s : %d\n", name, i);
        	}
    	}
}

Thread 클래스를 상속한 Thread1, Thread2, Thread3 클래스 각각에서 오버라이딩한 메소드가 모두 동일한 testMethod()를 호출하였다. 이 메소드는 synchronized 메소드이므로 모든 스레드가 공유하는 형태가 된다. 한 스레드가 testMethod()를 수행 중이면 종료되기 전까지 다른 스레드가 메소드를 호출하더라도 실행되지 못하고 대기해야한다.

 

728x90