자바 - 멀티스레딩

in #kr-dev3 years ago

자바 - 멀티스레딩


Java는 다중 스레드 프로그래밍 언어 이므로 Java를 사용하여 다중 스레드 프로그램을 개발할 수 있습니다. 다중 스레드 프로그램은 동시에 실행할 수 있는 둘 이상의 부분을 포함하고 각 부분은 특히 컴퓨터에 여러 CPU가 있는 경우 사용 가능한 리소스를 최적으로 사용하여 다른 작업을 동시에 처리할 수 있습니다.

정의에 따르면 멀티태스킹은 여러 프로세스가 CPU와 같은 공통 처리 리소스를 공유하는 경우입니다. 다중 스레딩은 단일 응용 프로그램 내의 특정 작업을 개별 스레드로 세분화할 수 있는 응용 프로그램으로 멀티태스킹의 개념을 확장합니다. 각 스레드는 병렬로 실행될 수 있습니다. OS는 서로 다른 응용 프로그램 간에 처리 시간을 분배할 뿐만 아니라 응용 프로그램 내의 각 스레드 간에도 처리 시간을 분배합니다.

다중 스레딩을 사용하면 동일한 프로그램에서 여러 활동이 동시에 진행될 수 있는 방식으로 작성할 수 있습니다.

스레드의 수명 주기

스레드는 수명 주기의 다양한 단계를 거칩니다. 예를 들어, 스레드는 생성, 시작, 실행 및 종료됩니다. 다음 다이어그램은 스레드의 전체 수명 주기를 보여줍니다.

자바 스레드

다음은 라이프 사이클의 단계입니다.

  • New - 새 스레드는 새 상태에서 수명 주기를 시작합니다. 프로그램이 스레드를 시작할 때까지 이 상태를 유지합니다. 또한 태어난 스레드 라고도 합니다 .

  • Runnable - 새로 생성된 스레드가 시작된 후 스레드가 실행 가능하게 됩니다. 이 상태의 스레드는 작업을 실행 중인 것으로 간주됩니다.

  • Waiting - 스레드가 다른 스레드가 작업을 수행하기를 기다리는 동안 스레드가 대기 상태로 전환되는 경우가 있습니다. 스레드는 다른 스레드가 계속 실행하도록 대기 중인 스레드에 신호를 보낼 때만 실행 가능한 상태로 다시 전환합니다.

  • Timed Waiting - 실행 가능한 스레드는 지정된 시간 간격 동안 시간이 지정된 대기 상태에 들어갈 수 있습니다. 이 상태의 스레드는 해당 시간 간격이 만료되거나 대기 중인 이벤트가 발생할 때 실행 가능한 상태로 다시 전환됩니다.

  • Terminated (Dead) - 실행 가능한 스레드는 작업을 완료하거나 다른 방식으로 종료될 때 종료된 상태로 들어갑니다.

스레드 우선 순위

모든 Java 스레드에는 운영 체제가 스레드가 예약된 순서를 결정하는 데 도움이 되는 우선 순위가 있습니다.

Java 스레드 우선순위는 MIN_PRIORITY(상수 1)와 MAX_PRIORITY(상수 10) 사이입니다. 기본적으로 모든 스레드에는 NORM_PRIORITY(상수 5)의 우선 순위가 지정됩니다.

우선 순위가 높은 스레드는 프로그램에 더 중요하며 우선 순위가 낮은 스레드보다 먼저 프로세서 시간을 할당해야 합니다. 그러나 스레드 우선 순위는 스레드가 실행되는 순서를 보장할 수 없으며 플랫폼에 크게 의존합니다.

실행 가능한 인터페이스를 구현하여 스레드 생성

클래스가 스레드로 실행되도록 의도된 경우 Runnable 인터페이스를 구현하여 이를 달성할 수 있습니다. 다음 세 가지 기본 단계를 따라야 합니다.

1 단계

첫 번째 단계로 Runnable 인터페이스 에서 제공하는 run() 메서드를 구현해야 합니다 . 이 메서드는 스레드에 대한 진입점을 제공하며 이 메서드 안에 완전한 비즈니스 논리를 넣습니다. 다음은 run() 메서드의 간단한 구문입니다.

public void run( )

2 단계

두 번째 단계로 다음 생성자를 사용하여 Thread 개체를 인스턴스화합니다.

Thread(Runnable threadObj, String threadName);

여기서, threadObj 는 Runnable 인터페이스 를 구현하는 클래스의 인스턴스 이고 threadName 은 새 스레드에 지정된 이름입니다.

3단계

Thread 객체가 생성되면 run() 메서드 호출을 실행하는 start() 메서드를 호출하여 시작할 수 있습니다. 다음은 start() 메서드의 간단한 구문입니다.

void start();

예시

다음은 새 스레드를 만들고 실행을 시작하는 예입니다.

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;
   
   RunnableDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      RunnableDemo R1 = new RunnableDemo( "Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo( "Thread-2");
      R2.start();
   }   
}

이것은 다음 결과를 생성합니다 -

산출

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

스레드 클래스를 확장하여 스레드 생성

스레드를 만드는 두 번째 방법 은 다음 두 가지 간단한 단계를 사용하여 스레드 클래스를 확장하는 새 클래스를 만드는 것입니다. 이 접근 방식은 Thread 클래스에서 사용 가능한 메서드를 사용하여 생성된 여러 스레드를 보다 유연하게 처리합니다.

1 단계

Thread 클래스에서 사용할 수 있는 run() 메서드 를 재정의해야 합니다 . 이 메서드는 스레드에 대한 진입점을 제공하며 이 메서드 안에 완전한 비즈니스 논리를 넣습니다. 다음은 run() 메서드의 간단한 구문입니다.

public void run( )

2 단계

Thread 객체가 생성되면 run() 메서드 호출을 실행하는 start() 메서드를 호출하여 시작할 수 있습니다. 다음은 start() 메서드의 간단한 구문입니다.

void start( );

예시

다음은 스레드를 확장하기 위해 재작성된 이전 프로그램입니다.

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   
   ThreadDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);
            // Let the thread sleep for a while.
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo( "Thread-1");
      T1.start();
      
      ThreadDemo T2 = new ThreadDemo( "Thread-2");
      T2.start();
   }   
}

이것은 다음 결과를 생성합니다 -

산출

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

스레드 메서드

다음은 Thread 클래스에서 사용할 수 있는 중요한 메서드 목록입니다.

씨.아니.방법 및 설명
1

공개 무효 시작()

별도의 실행 경로에서 스레드를 시작한 다음 이 Thread 개체에서 run() 메서드를 호출합니다.

|
| 2 |

공개 무효 실행()

이 Thread 개체가 별도의 Runnable 대상을 사용하여 인스턴스화된 경우 해당 Runnable 개체에서 run() 메서드가 호출됩니다.

|
| 삼 |

공개 최종 무효 setName(문자열 이름)

Thread 개체의 이름을 변경합니다. 이름을 검색하는 getName() 메서드도 있습니다.

|
| 4 |

공개 최종 무효 setPriority(int 우선 순위)

이 Thread 개체의 우선 순위를 설정합니다. 가능한 값은 1에서 10 사이입니다.

|
| 5 |

공개 최종 무효 setDaemon(부울 켜기)

true 매개변수는 이 스레드를 데몬 스레드로 나타냅니다.

|
| 6 |

공개 최종 무효 조인(긴 밀리초)

현재 스레드는 두 번째 스레드에서 이 메서드를 호출하여 두 번째 스레드가 종료되거나 지정된 시간(밀리초)이 지날 때까지 현재 스레드가 차단되도록 합니다.

|
| 7 |

공개 무효 인터럽트()

이 스레드를 인터럽트하여 어떤 이유로든 차단된 경우 실행을 계속합니다.

|
| 8 |

공개 최종 부울 isAlive()

스레드가 활성 상태이면 true를 반환합니다. 이는 스레드가 시작된 후 완료까지 실행되기 전입니다.

|

이전 메서드는 특정 Thread 개체에서 호출됩니다. Thread 클래스의 다음 메서드는 정적입니다. 정적 메서드 중 하나를 호출하면 현재 실행 중인 스레드에서 작업이 수행됩니다.

씨.아니.방법 및 설명
1

공개 정적 무효 수율()

현재 실행 중인 스레드가 예약을 기다리고 있는 동일한 우선 순위의 다른 스레드에 양보하도록 합니다.

|
| 2 |

public static void sleep(긴 밀리초)

현재 실행 중인 스레드가 지정된 시간(밀리초) 이상 동안 차단되도록 합니다.

|
| 삼 |

공개 정적 부울 홀드락(객체 x)

현재 스레드가 지정된 개체에 대한 잠금을 보유하고 있으면 true를 반환합니다.

|
| 4 |

공개 정적 스레드 currentThread()

이 메서드를 호출하는 스레드인 현재 실행 중인 스레드에 대한 참조를 반환합니다.

|
| 5 |

공개 정적 무효 dumpStack()

현재 실행 중인 스레드에 대한 스택 추적을 인쇄합니다. 이는 다중 스레드 응용 프로그램을 디버깅할 때 유용합니다.

|

예시

다음 ThreadClassDemo 프로그램은 Thread 클래스의 이러한 메서드 중 일부를 보여줍니다. Runnable 을 구현하는 DisplayMessage 클래스를 고려하십시오.

// File Name : DisplayMessage.java
// Create a thread to implement Runnable

public class DisplayMessage implements Runnable {
   private String message;
   
   public DisplayMessage(String message) {
      this.message = message;
   }
   
   public void run() {
      while(true) {
         System.out.println(message);
      }
   }
}

다음은 Thread 클래스를 확장하는 또 다른 클래스입니다.

// File Name : GuessANumber.java
// Create a thread to extentd Thread

public class GuessANumber extends Thread {
   private int number;
   public GuessANumber(int number) {
      this.number = number;
   }
   
   public void run() {
      int counter = 0;
      int guess = 0;
      do {
         guess = (int) (Math.random() * 100 + 1);
         System.out.println(this.getName() + " guesses " + guess);
         counter++;
      } while(guess != number);
      System.out.println("** Correct!" + this.getName() + "in" + counter + "guesses.**");
   }
}

다음은 위에서 정의한 클래스를 사용하는 주요 프로그램입니다.

// File Name : ThreadClassDemo.java
public class ThreadClassDemo {

   public static void main(String [] args) {
      Runnable hello = new DisplayMessage("Hello");
      Thread thread1 = new Thread(hello);
      thread1.setDaemon(true);
      thread1.setName("hello");
      System.out.println("Starting hello thread...");
      thread1.start();
      
      Runnable bye = new DisplayMessage("Goodbye");
      Thread thread2 = new Thread(bye);
      thread2.setPriority(Thread.MIN_PRIORITY);
      thread2.setDaemon(true);
      System.out.println("Starting goodbye thread...");
      thread2.start();

      System.out.println("Starting thread3...");
      Thread thread3 = new GuessANumber(27);
      thread3.start();
      try {
         thread3.join();
      } catch (InterruptedException e) {
         System.out.println("Thread interrupted.");
      }
      System.out.println("Starting thread4...");
      Thread thread4 = new GuessANumber(75);
      
      thread4.start();
      System.out.println("main() is ending...");
   }
}

그러면 다음과 같은 결과가 생성됩니다. 이 예제를 반복해서 시도할 수 있으며 매번 다른 결과를 얻을 수 있습니다.

산출

Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Goodbye
Goodbye
Goodbye
Goodbye
Goodbye
.......

Sort:  

[광고] STEEM 개발자 커뮤니티에 참여 하시면, 다양한 혜택을 받을 수 있습니다.

Coin Marketplace

STEEM 0.17
TRX 0.24
JST 0.034
BTC 95500.34
ETH 2808.64
SBD 0.66