자바 - 멀티스레딩

in kr-dev •  3 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
.......

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

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