ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JAVA] Thread와 Multi Thread
    Language/Java 2019. 11. 12. 20:50

     

    Thread란?

     

     

    우리가 프로그램을 작성하고 이 프로그램을 실행하면 그 '실행된 프로그램'을 프로세스라고 합니다. 그리고 프로세스 내부에 실제로 작업을 수행하고 처리하는 더 작은 단위를 스레드(Thread)라고 하는데요.

     

    하나의 프로세스에는 하나 이상의 스레드가 존재합니다. 스레드가 하나인 경우에는 프로그램 내의 모든 작업을 순차적으로 수행하지만, 스레드가 여러 개인 경우 각각의 스레드는 서로 다른 일을 동시에 수행할 수 있습니다.

     

    이는 멀티프로그래밍과는 다른 개념으로 멀티 프로그램은 여러 개의 프로세스가 동시에 돌아가는 것이지만, 멀티 스레드는 하나의 프로세스 내에서 이루어지는 작업입니다. 멀티프로그래밍의경우 각각의 프로세스 간의 동기화가 어렵다는 문제가 있습니다. 하지만 스레드는 서로 간에 생성한 인스턴스를 공유하므로 이러한 문제점을 보완할 수 있습니다.

     

    MultiThread는 언제 사용하지?

     

    대표적인 예로 게임을 구현이 있습니다. 질럿 10마리((객체)를 생성한 후, 5마리는 본진을 순회하고, 5마리는 공격에 나선다고 할 때 각 객체들이 서로 다른 상황에 서로 다른 동작을 할 것입니다. 이렇게 각 객체들이 각각의 특성을 가지고 동시에 서로 다른 동작을 수행할 때 멀티 스레드를 이용합니다.

     

    다른 예로는 속도 개선이 필요한 경우가 있습니다. 자원이 모두 확보되어 실행하는 환경에서 속도가 너무 느릴 때, 동시에 실행할 수 있는 작업을 병렬적으로 수행하면 더욱 빠르게 작업을 수행할 수 있습니다.

     

     

    그렇다면 자바에서 이러한 스레드를 활용해 프로그램을 구현하려면 어떻게 해야할까요?

    자바에서 스레드를 생성하는 방법은 두 가지입니다.

     

    1. Thread 클래스 상속

     

    자바에서 제공하는 Thread 클래스를 상속받아서 스레드를 생성할 수 있습니다.

     

    public class Test extends Thread {
    
    	public Test() {
    		setName("ThreadName");
    	}
        
    	public void run() {
    		// 수행할 내용
    	}
    }

     

    다음과 같이 Thread를 상속받은 클래스에 run() 메소드를 선언하고, 수행할 내용을 작성해줍니다. 그리고 생성자에서 setName() 메소드를 호출하면 이름을 지정해 줄 수 있습니다.

     

    이렇게 작성한 스레드를 호출하는 방법은 다음과 같습니다.

    public class Main {
    	public static void main(String[] args) {
    		Thread t = new Test();
    		t.start();
    		
    		// 또 다른 수행 내용
    	}
    
    }

     

    Thread를 상속받아 생성한 Test클래스 객체를 생성해 Thread변수로 선언하고, start() 메소드를 호출합니다. 그 아래에 또 다른 작업을 수행하는 코드를 작성하면 두 개의 thread가 동시에 수행됩니다.

     

    여기서 start() 메소드는 thread를 생성시켜 일을 시키기 위한 여러 준비 작업을 수행하고, 준비가 끝나면 run() 메소드를 호출해 thread가 작업을 수행하도록 합니다. 따라서 run() 메소드를 직접 호출하면 thread를 따로 생성해 작업을 수행하는 것이 아니라 그냥 메인thread에서 처리되므로 run() 메소드를 바로 호출하는 실수는 하지 않도록 주의해야 합니다.

    하지만 자바에서는 다중 상속이 불가능하기 때문에 Thread클래스를 상속받으면 다른 클래스를 상속받을 수 없다는 문제가 있습니다. 그래서 Runnable 인터페이스의 구현 객체를 통해 Thread를 생성하는 방법을 알아보겠습니다.

     

    2. Runnable 인터페이스

     

    public class Test implements Runnable {
    	public void run() {
    		// 수행할 내용
    	}
    }

     

    다음과 같이 Runnable인터페이스의 구현 객체에 run() 메소드를 선언해 수행할 내용을 작성합니다.

     

    public class Main {
    	public static void main(String[] args) {
    		Runnable r = new Test();
            	Thread t = new Thread(r);
    		t.start();
    		
    		// 또 다른 수행 내용
    	}
    
    }

     

    그리고 이렇게 만든 구현 객체를 생성하고 Runnable변수에 담아 Thread생성 시 매개변수로 넘겨줍니다. 실행시킬 때는 마찬가지로 start() 메소드를 호출합니다. 그러면 Thread의 run() 메소드 내부의 동작과 메인 thread내부의 작업이 동시에 이루어지게 됩니다.

     

    이렇게 동시에 서로 다른 작업을 처리하게 되면 생기는 치명적인 단점이 있습니다. 바로 공유되는 데이터의 무결성에 대한 문제인데요. 각각의 작업에 영향을 주지 않고 공유 데이터를 사용할 수 있도록 처리가 필요합니다.

     

    동시성 제어(Synchronized)

     

    synchronized키워드가 바로 그 역할을 합니다. 메소드에 또는 블록에 붙어서 해당 코드를 동시에 여러 스레드가 접근하지 못하도록 하는데요. 

     

    예를 들어, 은행 계좌에 10원씩 100번 입금하는 100개의 스레드가 동시에 돌아간다고 합시다. 제대로 동작한다면 모든 스레드가 수행을 마쳤을 때 100000원이 되어야 하지만 동시성 제어가 되지 않는다면 올바른 값을 보장할 수 없습니다. 이때, 입금을 수행하는 메소드에 synchronized 키워드를 붙여주면 해당 메소드는 한 번에 하나의 스레드만이 접근할 수 있습니다. 

     

    https://post.naver.com/viewer/postView.nhn?volumeNo=8045227&memberNo=30800755

     

    JAVA, 잡았다 | 25강, Java 멀티스레드 2 - 동시성 제어

    [BY PLAY with EXEM] JAVA를 잡았다. 마지막 낚시질 안녕은 영원한 헤어짐은 아니겠지요...... 드디어 ...

    m.post.naver.com

     

    위 블로그에 synchronized에 대한 좋은 예제가 있어 가져와 봤습니다.

     

    synchronized를 메소드에 붙이는 경우 한 번에 하나의 스레드가 메소드에 접근할 수 있습니다. 즉, 스레드가 수행되는 중간에는 각각의 스레드가 순서없이 메소드에 접근할 수 있습니다. 그런데 만약 각각의 스레드가 수행을 마칠 때까지 다른 스레드가 공유 데이터에 접근하는 것을 막고 싶다면 블록 자체에 synchronized키워드를 붙임으로써 가능하게 할 수 있습니다.

     

    이렇게 synchronized키워드를 이용하면 각 스레드의 순서를 제어할 수는 있지만, 좀 더 나아가 어떠한 조건에 따라 스레드를 제어할 수는 없을까?

     

    synchronized키워드와 함께 wait(), notify() 메소드를 이용하면 가능합니다. 조건을 주고(if 문) 이를 만족하지 않으면(혹은 만족하면)wait() 메소드를 호출해 스레드를 대기시키고, 조건을 만족할 때 notify() 메소드를 호출시켜 대기 중인  스레드 중 가장 우선순위가 높은 스레드를 깨워 실행시킵니다. notifyAll() 메소드를 호출시키면 대기중인 모든 스레드를 깨울 수 있습니다.

     

     

     

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

    [JAVA] Reader/Writer  (0) 2019.12.07
    [JAVA] InputStream/OutputStream  (0) 2019.12.07
    [JAVA] 다형성(Polymorphism)  (0) 2019.11.09
    [JAVA] 추상클래스와 인터페이스  (0) 2019.11.09
    [JAVA] String 생성 방법(new / literal)  (0) 2019.10.20
Designed by Tistory.