자바 동시성-빠른 가이드

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

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

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

스레드의 수명주기

스레드는 수명주기에서 다양한 단계를 거칩니다. 예를 들어 스레드가 생성되고 시작되고 실행 된 다음 죽습니다. 다음 다이어그램은 스레드의 전체 수명주기를 보여줍니다.

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

  • New− 새 스레드는 새 상태에서 수명주기를 시작합니다. 프로그램이 스레드를 시작할 때까지이 상태를 유지합니다. 또한born thread.

  • Runnable− 새로 태어난 스레드가 시작된 후 스레드가 실행 가능해집니다. 이 상태의 스레드는 작업을 실행하는 것으로 간주됩니다.

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

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

  • Terminated (Dead) − 실행 가능한 스레드는 작업을 완료하거나 그렇지 않으면 종료 될 때 종료 됨 상태에 들어갑니다.

스레드 우선 순위

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

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

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

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

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

1 단계

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

public void run( )

2 단계

두 번째 단계로 Thread 다음 생성자를 사용하여 객체-

Thread(Runnable threadObj, String threadName);

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

3 단계

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

void start();

Example

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

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();
   }   
}

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

Output

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다음 두 가지 간단한 단계를 사용하여 클래스. 이 접근 방식은 Thread 클래스에서 사용 가능한 메서드를 사용하여 생성 된 여러 스레드를 처리하는 데 더 많은 유연성을 제공합니다.

1 단계

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

public void run( )

2 단계

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

void start( );

Example

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

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();
   }   
}

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

Output

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.

이 장에서는 Java에 적합한 환경을 설정하는 다양한 측면에 대해 설명합니다.

지역 환경 설정

여전히 Java 프로그래밍 언어에 대한 환경을 설정하려는 경우이 섹션에서는 시스템에서 Java를 다운로드하고 설정하는 방법을 안내합니다. 다음은 환경을 설정하는 단계입니다.

Java SE는 Java 다운로드 링크에서 무료로 사용할 수 있습니다 . 운영 체제에 따라 버전을 다운로드 할 수 있습니다.

지침에 따라 Java를 다운로드하고 .exe컴퓨터에 Java를 설치합니다. 시스템에 Java를 설치 한 후에는 올바른 설치 디렉토리를 가리 키도록 환경 변수를 설정해야합니다.

Windows 용 경로 설정

c : \ Program Files \ java \ jdk 디렉토리에 Java를 설치했다고 가정합니다 .

  • '내 컴퓨터'를 마우스 오른쪽 버튼으로 클릭하고 '속성'을 선택합니다.

  • '고급'탭에서 '환경 변수'버튼을 클릭합니다.

  • 이제 Java 실행 파일의 경로도 포함하도록 'Path'변수를 변경하십시오. 예를 들어 현재 경로가 'C : \ WINDOWS \ SYSTEM32'로 설정된 경우 경로를 'C : \ WINDOWS \ SYSTEM32; c : \ Program Files \ java \ jdk \ bin'으로 변경합니다.

Linux, UNIX, Solaris, FreeBSD에 대한 경로 설정

환경 변수 PATH는 Java 바이너리가 설치된 위치를 가리 키도록 설정되어야합니다. 이 작업을 수행하는 데 문제가 있으면 쉘 문서를 참조하십시오.

예를 들어 bash 를 셸로 사용하는 경우 '.bashrc : export PATH = / path / to / java : $ PATH'끝에 다음 줄을 추가합니다.

인기있는 자바 편집자

Java 프로그램을 작성하려면 텍스트 편집기가 필요합니다. 시장에는 훨씬 더 정교한 IDE가 있습니다. 그러나 지금은 다음 중 하나를 고려할 수 있습니다.

  • Notepad − Windows 컴퓨터에서는 메모장 (이 자습서에 권장 됨), TextPad와 같은 간단한 텍스트 편집기를 사용할 수 있습니다.

  • Netbeans − 오픈 소스이며 무료로 제공되는 Java IDE https://netbeans.org/index.html.

  • Eclipse − Eclipse 오픈 소스 커뮤니티에서 개발 한 Java IDE이며 다음에서 다운로드 할 수 있습니다. https://www.eclipse.org/.

Core Java는 다중 스레드 프로그램에 대한 완전한 제어를 제공합니다. 요구 사항에 따라 일시 중지, 재개 또는 완전히 중지 할 수있는 다중 스레드 프로그램을 개발할 수 있습니다. 스레드 개체에서 동작을 제어하는 ​​데 사용할 수있는 다양한 정적 메서드가 있습니다. 다음 표에는 이러한 방법이 나열되어 있습니다.

Sr. 아니. 방법 및 설명
1

public void suspend()

이 메서드는 스레드를 일시 중단 된 상태로 만들고 resume () 메서드를 사용하여 다시 시작할 수 있습니다.

2

public void stop()

이 메서드는 스레드를 완전히 중지합니다.

public void resume()

이 메서드는 suspend () 메서드를 사용하여 일시 중단 된 스레드를 다시 시작합니다.

4

public void wait()

다른 스레드가 notify ()를 호출 할 때까지 현재 스레드가 대기하도록합니다.

5

public void notify()

이 개체의 모니터에서 대기중인 단일 스레드를 깨 웁니다.

최신 버전의 Java에서는 suspend (), resume () 및 stop () 메서드를 더 이상 사용하지 않으므로 사용 가능한 대안을 사용해야합니다.

class RunnableDemo implements Runnable {
   public Thread t;
   private String threadName;
   boolean suspended = false;

   RunnableDemo(String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );

      try {
         
         for(int i = 10; i > 0; i--) {
            System.out.println("Thread: " + threadName + ", " + i);

            // Let the thread sleep for a while.
            Thread.sleep(300);

            synchronized(this) {
               
               while(suspended) {
                  wait();
               }
            }
         }
      } 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 ();
      }
   }
   
   void suspend() {
      suspended = true;
   }
   
   synchronized void resume() {
      suspended = false;
      notify();
   }
}

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();

      try {
         Thread.sleep(1000);
         R1.suspend();
         System.out.println("Suspending First Thread");
         Thread.sleep(1000);
         R1.resume();
         System.out.println("Resuming First Thread");
         
         R2.suspend();
         System.out.println("Suspending thread Two");
         Thread.sleep(1000);
         R2.resume();
         System.out.println("Resuming thread Two");
      } catch (InterruptedException e) {
         System.out.println("Main thread Interrupted");
      } try {
         System.out.println("Waiting for threads to finish.");
         R1.t.join();
         R2.t.join();
      } catch (InterruptedException e) {
         System.out.println("Main thread Interrupted");
      }
      System.out.println("Main thread exiting.");
   }
}

위의 프로그램은 다음과 같은 출력을 생성합니다-

산출

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 10
Running Thread-2
Thread: Thread-2, 10
Thread: Thread-1, 9
Thread: Thread-2, 9
Thread: Thread-1, 8
Thread: Thread-2, 8
Thread: Thread-1, 7
Thread: Thread-2, 7
Suspending First Thread
Thread: Thread-2, 6
Thread: Thread-2, 5
Thread: Thread-2, 4
Resuming First Thread
Suspending thread Two
Thread: Thread-1, 6
Thread: Thread-1, 5
Thread: Thread-1, 4
Thread: Thread-1, 3
Resuming thread Two
Thread: Thread-2, 3
Waiting for threads to finish.
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
Main thread exiting.

프로세스 간 통신을 알고 있다면 스레드 간 통신을 쉽게 이해할 수 있습니다. 스레드 간 통신은 두 개 이상의 스레드가 일부 정보를 교환하는 응용 프로그램을 개발할 때 중요합니다.

스레드 통신을 가능하게하는 세 가지 간단한 방법과 약간의 트릭이 있습니다. 세 가지 방법은 모두 아래에 나열되어 있습니다.

Sr. 아니. 방법 및 설명
1

public void wait()

다른 스레드가 notify ()를 호출 할 때까지 현재 스레드가 대기하도록합니다.

2

public void notify()

이 개체의 모니터에서 대기중인 단일 스레드를 깨 웁니다.

public void notifyAll()

동일한 객체에서 wait ()를 호출 한 모든 스레드를 깨 웁니다.

이러한 방법은 다음과 같이 구현되었습니다. finalObject의 메서드를 사용하므로 모든 클래스에서 사용할 수 있습니다. 세 가지 메서드는 모두 내부에서만 호출 할 수 있습니다.synchronized 문맥.

이 예는 두 스레드가 wait()notify()방법. 동일한 개념을 사용하여 복잡한 시스템을 만들 수 있습니다.

class Chat {
   boolean flag = false;

   public synchronized void Question(String msg) {

      if (flag) {
         
         try {
            wait();
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
      System.out.println(msg);
      flag = true;
      notify();
   }

   public synchronized void Answer(String msg) {

      if (!flag) {
         
         try {
            wait();
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
      System.out.println(msg);
      flag = false;
      notify();
   }
}

class T1 implements Runnable {
   Chat m;
   String[] s1 = { "Hi", "How are you ?", "I am also doing fine!" };

   public T1(Chat m1) {
      this.m = m1;
      new Thread(this, "Question").start();
   }

   public void run() {
   
      for (int i = 0; i < s1.length; i++) {
         m.Question(s1[i]);
      }
   }
}

class T2 implements Runnable {
   Chat m;
   String[] s2 = { "Hi", "I am good, what about you?", "Great!" };

   public T2(Chat m2) {
      this.m = m2;
      new Thread(this, "Answer").start();
   }

   public void run() {

      for (int i = 0; i < s2.length; i++) {
         m.Answer(s2[i]);
      }
   }
}

public class TestThread {

   public static void main(String[] args) {
      Chat m = new Chat();
      new T1(m);
      new T2(m);
   }
}

위의 프로그램을 따라 실행하면 다음과 같은 결과가 나옵니다.

산출

Hi
Hi
How are you ?
I am good, what about you?
I am also doing fine!
Great!

위의 예는 [https://stackoverflow.com/questions/2170520/inter-thread-communication-in-java]에서 가져와 수정되었습니다.

동기화를 사용한 다중 스레딩 예제

다음은 카운터 값을 순서대로 인쇄하는 동일한 예제이며 실행할 때마다 동일한 결과를 생성합니다.

class PrintDemo {
   
   public void printCount() {
      
      try {
         
         for(int i = 5; i > 0; i--) {
            System.out.println("Counter   ---   "  + i );
         }
      } catch (Exception e) {
         System.out.println("Thread  interrupted.");
      }
   }
}

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   PrintDemo  PD;

   ThreadDemo(String name,  PrintDemo pd) {
      threadName = name;
      PD = pd;
   }
   
   public void run() {
      
      synchronized(PD) {
         PD.printCount();
      }
      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[]) {
      PrintDemo PD = new PrintDemo();

      ThreadDemo T1 = new ThreadDemo("Thread - 1 ", PD);
      ThreadDemo T2 = new ThreadDemo("Thread - 2 ", PD);

      T1.start();
      T2.start();

      // wait for threads to end
      try {
         T1.join();
         T2.join();
      } catch (Exception e) {
         System.out.println("Interrupted");
      }
   }
}

이 프로그램을 실행할 때마다 동일한 결과가 생성됩니다.

산출

Starting Thread - 1
Starting Thread - 2
Counter   ---   5
Counter   ---   4
Counter   ---   3
Counter   ---   2
Counter   ---   1
Thread Thread - 1  exiting.
Counter   ---   5
Counter   ---   4
Counter   ---   3
Counter   ---   2
Counter   ---   1
Thread Thread - 2  exiting.

교착 상태는 둘 이상의 스레드가 서로를 기다리면서 영원히 차단되는 상황을 나타냅니다. 교착 상태는 여러 스레드에 동일한 잠금이 필요하지만 다른 순서로 획득 할 때 발생합니다. Java 다중 스레드 프로그램은 다음과 같은 이유로 교착 상태가 발생할 수 있습니다.synchronized키워드는 지정된 개체와 관련된 잠금 또는 모니터를 기다리는 동안 실행 스레드가 차단되도록합니다. 여기에 예가 있습니다.

public class TestThread {
   public static Object Lock1 = new Object();
   public static Object Lock2 = new Object();
   
   public static void main(String args[]) {
      ThreadDemo1 T1 = new ThreadDemo1();
      ThreadDemo2 T2 = new ThreadDemo2();
      T1.start();
      T2.start();
   }
   
   private static class ThreadDemo1 extends Thread {
   
      public void run() {
      
         synchronized (Lock1) {
            System.out.println("Thread 1: Holding lock 1...");

            try {
               Thread.sleep(10);
            } catch (InterruptedException e) {}
            System.out.println("Thread 1: Waiting for lock 2...");

            synchronized (Lock2) {
               System.out.println("Thread 1: Holding lock 1 & 2...");
            }
         }
      }
   }

   private static class ThreadDemo2 extends Thread {
   
      public void run() {
      
         synchronized (Lock2) {
            System.out.println("Thread 2: Holding lock 2...");
            
            try {
               Thread.sleep(10);
            } catch (InterruptedException e) {}
            System.out.println("Thread 2: Waiting for lock 1...");
            
            synchronized (Lock1) {
               System.out.println("Thread 2: Holding lock 1 & 2...");
            }
         }
      }
   } 
}

위의 프로그램을 컴파일하고 실행하면 교착 상태 상황을 발견하고 다음은 프로그램에서 생성 된 출력입니다.

산출

Thread 1: Holding lock 1...
Thread 2: Holding lock 2...
Thread 1: Waiting for lock 2...
Thread 2: Waiting for lock 1...

위의 프로그램은 진행할 위치에있는 스레드 중 어느 것도 잠금을 해제 할 때까지 기다리지 않기 때문에 영원히 중단됩니다. 따라서 Ctrl + C를 눌러 프로그램을 종료 할 수 있습니다.

교착 상태 솔루션 예

두 스레드가 여전히 서로를 기다리는 지 확인하기 위해 동일한 프로그램의 잠금 및 실행 순서를 변경해 보겠습니다.

public class TestThread {
   public static Object Lock1 = new Object();
   public static Object Lock2 = new Object();
   
   public static void main(String args[]) {
      ThreadDemo1 T1 = new ThreadDemo1();
      ThreadDemo2 T2 = new ThreadDemo2();
      T1.start();
      T2.start();
   }
   
   private static class ThreadDemo1 extends Thread {
   
      public void run() {
         
         synchronized (Lock1) {
            System.out.println("Thread 1: Holding lock 1...");
            
            try {
               Thread.sleep(10);
            } catch (InterruptedException e) {}
            System.out.println("Thread 1: Waiting for lock 2...");

            synchronized (Lock2) {
               System.out.println("Thread 1: Holding lock 1 & 2...");
            }
         }
      }
   }

   private static class ThreadDemo2 extends Thread {
      
      public void run() {
         
         synchronized (Lock1) {
            System.out.println("Thread 2: Holding lock 1...");
           
            try {
               Thread.sleep(10);
            } catch (InterruptedException e) {}
            System.out.println("Thread 2: Waiting for lock 2...");

            synchronized (Lock2) {
               System.out.println("Thread 2: Holding lock 1 & 2...");
            }
         }
      }
   } 
}

따라서 잠금 순서를 변경하는 것만으로도 프로그램이 교착 상태에 빠지는 것을 방지하고 다음과 같은 결과로 완료됩니다.

산출

Thread 1: Holding lock 1...
Thread 1: Waiting for lock 2...
Thread 1: Holding lock 1 & 2...
Thread 2: Holding lock 1...
Thread 2: Waiting for lock 2...
Thread 2: Holding lock 1 & 2...

위의 예는 개념을 명확하게하기위한 것이지만 복잡한 개념이므로 교착 상태 상황을 처리하기 위해 응용 프로그램을 개발하기 전에 자세히 살펴 봐야합니다.

ThreadLocal 클래스는 동일한 스레드에서만 읽고 쓸 수있는 스레드 로컬 변수를 만드는 데 사용됩니다. 예를 들어, 두 스레드가 동일한 threadLocal 변수에 대한 참조를 갖는 코드에 액세스하는 경우 각 스레드는 다른 스레드가 수행 한 threadLocal 변수에 대한 수정 사항을 볼 수 없습니다.

ThreadLocal 메서드

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

Sr. 아니. 방법 및 설명
1

public T get()

이 스레드 로컬 변수의 현재 스레드 복사본에있는 값을 반환합니다.

2

protected T initialValue()

이 스레드 로컬 변수에 대한 현재 스레드의 "초기 값"을 반환합니다.

public void remove()

이 스레드 로컬 변수에 대한 현재 스레드의 값을 제거합니다.

4

public void set(T value)

이 스레드 로컬 변수의 현재 스레드 복사본을 지정된 값으로 설정합니다.

다음 TestThread 프로그램은 ThreadLocal 클래스의 이러한 메서드 중 일부를 보여줍니다. 여기서 우리는 두 개의 카운터 변수를 사용했는데, 하나는 일반 변수이고 다른 하나는 ThreadLocal입니다.

class RunnableDemo implements Runnable {
   int counter;
   ThreadLocal<Integer> threadLocalCounter = new ThreadLocal<Integer>();

   public void run() {     
      counter++;

      if(threadLocalCounter.get() != null) {
         threadLocalCounter.set(threadLocalCounter.get().intValue() + 1);
      } else {
         threadLocalCounter.set(0);
      }
      System.out.println("Counter: " + counter);
      System.out.println("threadLocalCounter: " + threadLocalCounter.get());
   }
}

public class TestThread {

   public static void main(String args[]) {
      RunnableDemo commonInstance = new RunnableDemo();

      Thread t1 = new Thread(commonInstance);
      Thread t2 = new Thread(commonInstance);
      Thread t3 = new Thread(commonInstance);
      Thread t4 = new Thread(commonInstance);

      t1.start();
      t2.start();
      t3.start();
      t4.start();

      // wait for threads to end
      try {
         t1.join();
         t2.join();
         t3.join();
         t4.join();
      } catch (Exception e) {
         System.out.println("Interrupted");
      }
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Counter: 1
threadLocalCounter: 0
Counter: 2
threadLocalCounter: 0
Counter: 3
threadLocalCounter: 0
Counter: 4
threadLocalCounter: 0

카운터 값은 스레드마다 증가하지만 threadLocalCounter는 각 스레드에 대해 0으로 유지됩니다.

java.util.concurrent.ThreadLocalRandom은 jdk 1.7부터 도입 된 유틸리티 클래스이며 난수를 생성하기 위해 다중 스레드 또는 ForkJoinTask가 필요할 때 유용합니다. 성능이 향상되고 Math.random () 메서드보다 경합이 적습니다.

ThreadLocalRandom 메서드

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

Sr. 아니. 방법 및 설명
1

public static ThreadLocalRandom current()

현재 스레드의 ThreadLocalRandom을 반환합니다.

2

protected int next(int bits)

다음 의사 난수를 생성합니다.

public double nextDouble(double n)

0 (포함)과 지정된 값 (제외) 사이에 균일하게 분포 된 의사 난수 double 값을 반환합니다.

4

public double nextDouble(double least, double bound)

주어진 최소값 (포함)과 바운드 (배타적) 사이에 균일하게 분포 된 의사 난수 값을 반환합니다.

5

public int nextInt(int least, int bound)

주어진 최소값 (포함)과 바운드 (배타적) 사이에 균일하게 분포 된 의사 난수 값을 반환합니다.

6

public long nextLong(long n)

0 (포함)과 지정된 값 (제외) 사이에 균일하게 분포 된 의사 난수 값을 반환합니다.

7

public long nextLong(long least, long bound)

주어진 최소값 (포함)과 바운드 (배타적) 사이에 균일하게 분포 된 의사 난수 값을 반환합니다.

8

public void setSeed(long seed)

UnsupportedOperationException이 발생합니다.

다음 TestThread 프로그램은 Lock 인터페이스의 이러한 메소드 중 일부를 보여줍니다. 여기서 우리는 lock ()을 사용하여 잠금을 획득하고 unlock ()을 사용하여 잠금을 해제했습니다.

import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.ThreadLocalRandom;

public class TestThread {
  
   public static void main(final String[] arguments) {
      System.out.println("Random Integer: " + new Random().nextInt());  
      System.out.println("Seeded Random Integer: " + new Random(15).nextInt());  
      System.out.println(
         "Thread Local Random Integer: " + ThreadLocalRandom.current().nextInt());
      
      final ThreadLocalRandom random = ThreadLocalRandom.current();  
      random.setSeed(15); //exception will come as seeding is not allowed in ThreadLocalRandom.
      System.out.println("Seeded Thread Local Random Integer: " + random.nextInt());  
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Random Integer: 1566889198
Seeded Random Integer: -1159716814
Thread Local Random Integer: 358693993
Exception in thread "main" java.lang.UnsupportedOperationException
        at java.util.concurrent.ThreadLocalRandom.setSeed(Unknown Source)
        at TestThread.main(TestThread.java:21)

여기서는 난수를 얻기 위해 ThreadLocalRandom과 Random 클래스를 사용했습니다.

java.util.concurrent.locks.Lock 인터페이스는 동기화 된 블록과 유사한 스레드 동기화 메커니즘으로 사용됩니다. 새로운 잠금 메커니즘은 동기화 된 블록보다 더 유연하고 더 많은 옵션을 제공합니다. 잠금과 동기화 된 블록의 주요 차이점은 다음과 같습니다.

  • Guarantee of sequence− 동기화 된 블록은 대기중인 스레드에게 액세스 권한이 부여되는 순서를 보장하지 않습니다. 잠금 인터페이스가 처리합니다.

  • No timeout− 동기화 된 블록은 잠금이 허용되지 않은 경우 타임 아웃 옵션이 없습니다. 잠금 인터페이스는 이러한 옵션을 제공합니다.

  • Single method − 동기화 된 블록은 단일 메소드 내에 완전히 포함되어야하지만 잠금 인터페이스의 메소드 lock () 및 unlock ()은 다른 메소드에서 호출 될 수 있습니다.

잠금 방법

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

Sr. 아니. 방법 및 설명
1

public void lock()

잠금을 획득합니다.

2

public void lockInterruptibly()

현재 스레드가 중단되지 않는 한 잠금을 획득합니다.

public Condition newCondition()

이 Lock 인스턴스에 바인딩 된 새 Condition 인스턴스를 반환합니다.

4

public boolean tryLock()

호출시 잠금이 해제 된 경우에만 잠금을 획득합니다.

5

public boolean tryLock()

호출시 잠금이 해제 된 경우에만 잠금을 획득합니다.

6

public boolean tryLock(long time, TimeUnit unit)

주어진 대기 시간 내에 잠금이 해제되고 현재 스레드가 중단되지 않은 경우 잠금을 획득합니다.

7

public void unlock()

잠금을 해제합니다.

다음 TestThread 프로그램은 Lock 인터페이스의 이러한 메소드 중 일부를 보여줍니다. 여기서 우리는 lock ()을 사용하여 잠금을 획득하고 unlock ()을 사용하여 잠금을 해제했습니다.

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class PrintDemo {
   private final Lock queueLock = new ReentrantLock();

   public void print() {
      queueLock.lock();

      try {
         Long duration = (long) (Math.random() * 10000);
         System.out.println(Thread.currentThread().getName() 
            + "  Time Taken " + (duration / 1000) + " seconds.");
         Thread.sleep(duration);
      } catch (InterruptedException e) {
         e.printStackTrace();
      } finally {
         System.out.printf(
            "%s printed the document successfully.\n", Thread.currentThread().getName());
         queueLock.unlock();
      }
   }
}

class ThreadDemo extends Thread {
   PrintDemo  printDemo;

   ThreadDemo(String name,  PrintDemo printDemo) {
      super(name);
      this.printDemo = printDemo;
   }   

   @Override
   public void run() {
      System.out.printf(
         "%s starts printing a document\n", Thread.currentThread().getName());
      printDemo.print();
   }
}

public class TestThread {

   public static void main(String args[]) {
      PrintDemo PD = new PrintDemo();

      ThreadDemo t1 = new ThreadDemo("Thread - 1 ", PD);
      ThreadDemo t2 = new ThreadDemo("Thread - 2 ", PD);
      ThreadDemo t3 = new ThreadDemo("Thread - 3 ", PD);
      ThreadDemo t4 = new ThreadDemo("Thread - 4 ", PD);

      t1.start();
      t2.start();
      t3.start();
      t4.start();
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Thread - 1  starts printing a document
Thread - 4  starts printing a document
Thread - 3  starts printing a document
Thread - 2  starts printing a document
Thread - 1   Time Taken 4 seconds.
Thread - 1  printed the document successfully.
Thread - 4   Time Taken 3 seconds.
Thread - 4  printed the document successfully.
Thread - 3   Time Taken 5 seconds.
Thread - 3  printed the document successfully.
Thread - 2   Time Taken 4 seconds.
Thread - 2  printed the document successfully.

여기서는 Lock 인터페이스 구현으로 ReentrantLock 클래스를 사용했습니다. ReentrantLock 클래스를 사용하면 다른 메서드에 대한 잠금이 이미있는 경우에도 스레드가 메서드를 잠글 수 있습니다.

java.util.concurrent.locks.ReadWriteLock 인터페이스를 사용하면 여러 스레드를 한 번에 읽을 수 있지만 한 번에 하나의 스레드 만 쓸 수 있습니다.

  • Read Lock − 쓰기를 위해 ReadWriteLock을 잠근 스레드가 없으면 여러 스레드가 읽기 잠금에 액세스 할 수 있습니다.

  • Write Lock − 읽고 쓰는 스레드가 없으면 한 스레드가 쓰기 잠금에 액세스 할 수 있습니다.

잠금 방법

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

Sr. 아니. 방법 및 설명
1

public Lock readLock()

읽기에 사용 된 잠금을 반환합니다.

2

public Lock writeLock()

쓰기에 사용 된 잠금을 반환합니다.

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class TestThread {
   private static final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
   private static String message = "a";

   public static void main(String[] args) throws InterruptedException {
      Thread t1 = new Thread(new WriterA());
      t1.setName("Writer A");
      
      Thread t2 = new Thread(new WriterB());
      t2.setName("Writer B");
      
      Thread t3 = new Thread(new Reader());
      t3.setName("Reader");
      t1.start();
      t2.start();
      t3.start();
      t1.join();
      t2.join();
      t3.join();
   }

   static class Reader implements Runnable {

      public void run() {
         
         if(lock.isWriteLocked()) {
            System.out.println("Write Lock Present.");
         }
         lock.readLock().lock();

         try {
            Long duration = (long) (Math.random() * 10000);
            System.out.println(Thread.currentThread().getName() 
               + "  Time Taken " + (duration / 1000) + " seconds.");
            Thread.sleep(duration);
         } catch (InterruptedException e) {
            e.printStackTrace();
         } finally {
            System.out.println(Thread.currentThread().getName() +": "+ message );
            lock.readLock().unlock();
         }
      }
   }

   static class WriterA implements Runnable {

      public void run() {
         lock.writeLock().lock();
         
         try {
            Long duration = (long) (Math.random() * 10000);
            System.out.println(Thread.currentThread().getName() 
               + "  Time Taken " + (duration / 1000) + " seconds.");
            Thread.sleep(duration);
         } catch (InterruptedException e) {
            e.printStackTrace();
         } finally {
            message = message.concat("a");
            lock.writeLock().unlock();
         }
      }
   }

   static class WriterB implements Runnable {

      public void run() {
         lock.writeLock().lock();
         
         try {
            Long duration = (long) (Math.random() * 10000);
            System.out.println(Thread.currentThread().getName() 
               + "  Time Taken " + (duration / 1000) + " seconds.");
            Thread.sleep(duration);
         } catch (InterruptedException e) {
            e.printStackTrace();
         } finally {
            message = message.concat("b");
            lock.writeLock().unlock();
         }
      }
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Writer A  Time Taken 6 seconds.
Write Lock Present.
Writer B  Time Taken 2 seconds.
Reader  Time Taken 0 seconds.
Reader: aab

java.util.concurrent.locks.Condition 인터페이스는 주어진 조건이 참이 될 때까지 실행을 일시 중단하는 스레드 기능을 제공합니다. Condition 객체는 반드시 Lock에 바인딩되어야하며 newCondition () 메서드를 사용하여 가져옵니다.

조건 방법

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

Sr. 아니. 방법 및 설명
1

public void await()

현재 스레드가 신호를 받거나 중단 될 때까지 대기하도록합니다.

2

public boolean await(long time, TimeUnit unit)

현재 스레드가 신호를 받거나 인터럽트되거나 지정된 대기 시간이 경과 할 때까지 대기하도록합니다.

public long awaitNanos(long nanosTimeout)

현재 스레드가 신호를 받거나 인터럽트되거나 지정된 대기 시간이 경과 할 때까지 대기하도록합니다.

4

public long awaitUninterruptibly()

현재 스레드가 신호를받을 때까지 대기하도록합니다.

5

public long awaitUntil()

현재 스레드가 신호를 받거나 중단되거나 지정된 기한이 경과 할 때까지 대기하도록합니다.

6

public void signal()

대기중인 스레드 하나를 깨 웁니다.

7

public void signalAll()

대기중인 모든 스레드를 깨 웁니다.

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestThread {

   public static void main(String[] args) throws InterruptedException {
      ItemQueue itemQueue = new ItemQueue(10);

      //Create a producer and a consumer.
      Thread producer = new Producer(itemQueue);
      Thread consumer = new Consumer(itemQueue);

      //Start both threads.
      producer.start();
      consumer.start();

      //Wait for both threads to terminate.
      producer.join();
      consumer.join();
   }

   static class ItemQueue {
      private Object[] items = null;
      private int current = 0;
      private int placeIndex = 0;
      private int removeIndex = 0;

      private final Lock lock;
      private final Condition isEmpty;
      private final Condition isFull;

      public ItemQueue(int capacity) {
         this.items = new Object[capacity];
         lock = new ReentrantLock();
         isEmpty = lock.newCondition();
         isFull = lock.newCondition();
      }

      public void add(Object item) throws InterruptedException {
         lock.lock();

         while(current >= items.length)
            isFull.await();

         items[placeIndex] = item;
         placeIndex = (placeIndex + 1) % items.length;
         ++current;

         //Notify the consumer that there is data available.
         isEmpty.signal();
         lock.unlock();
      }

      public Object remove() throws InterruptedException {
         Object item = null;

         lock.lock();

         while(current <= 0) {
            isEmpty.await();
         }
         item = items[removeIndex];
         removeIndex = (removeIndex + 1) % items.length;
         --current;

         //Notify the producer that there is space available.
         isFull.signal();
         lock.unlock();

         return item;
      }

      public boolean isEmpty() {
         return (items.length == 0);
      }
   }

   static class Producer extends Thread {
      private final ItemQueue queue;
      
      public Producer(ItemQueue queue) {
         this.queue = queue;
      }

      @Override
      public void run() {
         String[] numbers =
            {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"};

         try {
            
            for(String number: numbers) {
               System.out.println("[Producer]: " + number);
            }
            queue.add(null);
         } catch (InterruptedException ex) {
            ex.printStackTrace();
         } 
      }
   }

   static class Consumer extends Thread {
      private final ItemQueue queue;
      
      public Consumer(ItemQueue queue) {
         this.queue = queue;
      }

      @Override
      public void run() {
         
         try {
            
            do {
               Object number = queue.remove();
               System.out.println("[Consumer]: " + number);

               if(number == null) {
                  return;
               }
            } while(!queue.isEmpty());
         } catch (InterruptedException ex) {
            ex.printStackTrace();
         }
      }
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

[Producer]: 1
[Producer]: 2
[Producer]: 3
[Producer]: 4
[Producer]: 5
[Producer]: 6
[Producer]: 7
[Producer]: 8
[Producer]: 9
[Producer]: 10
[Producer]: 11
[Producer]: 12
[Consumer]: null

java.util.concurrent.atomic.AtomicInteger 클래스는 원자 적으로 읽고 쓸 수있는 기본 int 값에 대한 연산을 제공하며 고급 원자 연산도 포함합니다. AtomicInteger는 기본 int 변수에 대한 원자 연산을 지원합니다. 휘발성 변수에 대한 읽기 및 쓰기처럼 작동하는 get 및 set 메서드가 있습니다. 즉, 세트는 동일한 변수에 대한 후속 get과 사전 발생 관계를 갖습니다. 원자 compareAndSet 메서드에는 이러한 메모리 일관성 기능도 있습니다.

AtomicInteger 메서드

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

Sr. 아니. 방법 및 설명
1

public int addAndGet(int delta)

주어진 값을 현재 값에 원자 적으로 더합니다.

2

public boolean compareAndSet(int expect, int update)

현재 값이 예상 값과 같으면 원자 적으로 값을 지정된 업데이트 된 값으로 설정합니다.

public int decrementAndGet()

원자 적으로 현재 값 1만큼 감소합니다.

4

public double doubleValue()

지정된 숫자의 값을 double로 반환합니다.

5

public float floatValue()

지정된 숫자의 값을 부동 소수점으로 반환합니다.

6

public int get()

현재 값을 가져옵니다.

7

public int getAndAdd(int delta)

주어진 값을 현재 값에 원자 적으로 더합니다.

8

public int getAndDecrement()

원자 적으로 현재 값 1만큼 감소합니다.

9

public int getAndIncrement()

현재 값을 원자 적으로 1 씩 증가시킵니다.

10

public int getAndSet(int newValue)

원자 적으로 주어진 값으로 설정하고 이전 값을 반환합니다.

11

public int incrementAndGet()

현재 값을 원자 적으로 1 씩 증가시킵니다.

12

public int intValue()

지정된 숫자의 값을 정수로 반환합니다.

13

public void lazySet(int newValue)

결국 주어진 값으로 설정됩니다.

14

public long longValue()

지정된 숫자의 값을 long으로 반환합니다.

15

public void set(int newValue)

주어진 값으로 설정합니다.

16

public String toString()

현재 값의 문자열 표현을 반환합니다.

17

public boolean weakCompareAndSet(int expect, int update)

현재 값이 예상 값과 같으면 원자 적으로 값을 지정된 업데이트 된 값으로 설정합니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 안전하지 않은 카운터 구현을 보여줍니다.

public class TestThread {

   static class Counter {
      private int c = 0;

      public void increment() {
         c++;
      }

      public int value() {
         return c;
      }
   }
   
   public static void main(final String[] arguments) throws InterruptedException {
      final Counter counter = new Counter();
      
      //1000 threads
      for(int i = 0; i < 1000 ; i++) {
         
         new Thread(new Runnable() {
            
            public void run() {
               counter.increment();
            }
         }).start(); 
      }  
      Thread.sleep(6000);
      System.out.println("Final number (should be 1000): " + counter.value());
   }  
}

이것은 컴퓨터의 속도와 스레드 인터리빙에 따라 다음과 같은 결과를 생성 할 수 있습니다.

산출

Final number (should be 1000): 1000

import java.util.concurrent.atomic.AtomicInteger;

public class TestThread {

   static class Counter {
      private AtomicInteger c = new AtomicInteger(0);

      public void increment() {
         c.getAndIncrement();
      }

      public int value() {
         return c.get();
      }
   }
   
   public static void main(final String[] arguments) throws InterruptedException {
      final Counter counter = new Counter();
      
      //1000 threads
      for(int i = 0; i < 1000 ; i++) {

         new Thread(new Runnable() {
            public void run() {
               counter.increment();
            }
         }).start(); 
      }  
      Thread.sleep(6000);
      System.out.println("Final number (should be 1000): " + counter.value());
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Final number (should be 1000): 1000

java.util.concurrent.atomic.AtomicLong 클래스는 원자 적으로 읽고 쓸 수있는 기본 long 값에 대한 연산을 제공하며 고급 원자 연산도 포함합니다. AtomicLong은 기본 long 변수에 대한 원자 연산을 지원합니다. 휘발성 변수에 대한 읽기 및 쓰기처럼 작동하는 get 및 set 메서드가 있습니다. 즉, 세트는 동일한 변수에 대한 후속 get과 사전 발생 관계를 갖습니다. 원자 compareAndSet 메서드에는 이러한 메모리 일관성 기능도 있습니다.

AtomicLong 메서드

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

Sr. 아니. 방법 및 설명
1

public long addAndGet(long delta)

주어진 값을 현재 값에 원자 적으로 더합니다.

2

public boolean compareAndSet(long expect, long update)

현재 값이 예상 값과 같으면 원자 적으로 값을 지정된 업데이트 된 값으로 설정합니다.

public long decrementAndGet()

원자 적으로 현재 값 1만큼 감소합니다.

4

public double doubleValue()

지정된 숫자의 값을 double로 반환합니다.

5

public float floatValue()

지정된 숫자의 값을 부동 소수점으로 반환합니다.

6

public long get()

현재 값을 가져옵니다.

7

public long getAndAdd(long delta)

주어진 값을 현재 값에 원자 적으로 더합니다.

8

public long getAndDecrement()

원자 적으로 현재 값 1만큼 감소합니다.

9

public long getAndIncrement()

현재 값을 원자 적으로 1 씩 증가시킵니다.

10

public long getAndSet(long newValue)

원자 적으로 주어진 값으로 설정하고 이전 값을 반환합니다.

11

public long incrementAndGet()

현재 값을 원자 적으로 1 씩 증가시킵니다.

12

public int intValue()

지정된 숫자의 값을 정수로 반환합니다.

13

public void lazySet(long newValue)

결국 주어진 값으로 설정됩니다.

14

public long longValue()

지정된 숫자의 값을 long으로 반환합니다.

15

public void set(long newValue)

주어진 값으로 설정합니다.

16

public String toString()

현재 값의 문자열 표현을 반환합니다.

17

public boolean weakCompareAndSet(long expect, long update)

현재 값이 예상 값과 같으면 원자 적으로 값을 지정된 업데이트 된 값으로 설정합니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 AtomicLong을 사용한 카운터의 안전한 구현을 보여줍니다.

import java.util.concurrent.atomic.AtomicLong;

public class TestThread {

   static class Counter {
      private AtomicLong c = new AtomicLong(0);

      public void increment() {
         c.getAndIncrement();
      }

      public long value() {
         return c.get();
      }
   }

   public static void main(final String[] arguments) throws InterruptedException {
      final Counter counter = new Counter();
      
      //1000 threads
      for(int i = 0; i < 1000 ; i++) {
         
         new Thread(new Runnable() {
            
            public void run() {
               counter.increment();
            }
         }).start();	
      }
      Thread.sleep(6000);			   		  
      System.out.println("Final number (should be 1000): " + counter.value());
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Final number (should be 1000): 1000

java.util.concurrent.atomic.AtomicBoolean 클래스는 원자 적으로 읽고 쓸 수있는 기본 부울 값에 대한 연산을 제공하며 고급 원자 연산도 포함합니다. AtomicBoolean은 기본 부울 변수에 대한 원자 연산을 지원합니다. 휘발성 변수에 대한 읽기 및 쓰기처럼 작동하는 get 및 set 메서드가 있습니다. 즉, 세트는 동일한 변수에 대한 후속 get과 사전 발생 관계를 갖습니다. 원자 compareAndSet 메서드에는 이러한 메모리 일관성 기능도 있습니다.

AtomicBoolean 메서드

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

Sr. 아니. 방법 및 설명
1

public boolean compareAndSet(boolean expect, boolean update)

현재 값 == 예상 값인 경우 값을 지정된 업데이트 된 값으로 원자 적으로 설정합니다.

2

public boolean get()

현재 값을 반환합니다.

public boolean getAndSet(boolean newValue)

원자 적으로 주어진 값으로 설정하고 이전 값을 반환합니다.

4

public void lazySet(boolean newValue)

결국 주어진 값으로 설정됩니다.

5

public void set(boolean newValue)

주어진 값으로 무조건 설정합니다.

6

public String toString()

현재 값의 문자열 표현을 반환합니다.

7

public boolean weakCompareAndSet(boolean expect, boolean update)

현재 값 == 예상 값인 경우 값을 지정된 업데이트 된 값으로 원자 적으로 설정합니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 AtomicBoolean 변수의 사용법을 보여줍니다.

import java.util.concurrent.atomic.AtomicBoolean;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      final AtomicBoolean atomicBoolean = new AtomicBoolean(false);

      new Thread("Thread 1") {

         public void run() {

            while(true) {
               System.out.println(Thread.currentThread().getName() 
                  +" Waiting for Thread 2 to set Atomic variable to true. Current value is "
                  + atomicBoolean.get());

               if(atomicBoolean.compareAndSet(true, false)) {
                  System.out.println("Done!");
                  break;
               }
            }
         };
      }.start();

      new Thread("Thread 2") {

         public void run() {
            System.out.println(Thread.currentThread().getName() +
               ", Atomic Variable: " +atomicBoolean.get()); 
            System.out.println(Thread.currentThread().getName() +
               " is setting the variable to true ");
            atomicBoolean.set(true);
            System.out.println(Thread.currentThread().getName() +
               ", Atomic Variable: " +atomicBoolean.get()); 
         };
      }.start();
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Thread 1 Waiting for Thread 2 to set Atomic variable to true. Current value is false
Thread 1 Waiting for Thread 2 to set Atomic variable to true. Current value is false
Thread 1 Waiting for Thread 2 to set Atomic variable to true. Current value is false
Thread 2, Atomic Variable: false
Thread 1 Waiting for Thread 2 to set Atomic variable to true. Current value is false
Thread 2 is setting the variable to true
Thread 2, Atomic Variable: true
Thread 1 Waiting for Thread 2 to set Atomic variable to true. Current value is false
Done!

java.util.concurrent.atomic.AtomicReference 클래스는 원자 적으로 읽고 쓸 수있는 기본 객체 참조에 대한 작업을 제공하며 고급 원자 작업도 포함합니다. AtomicReference는 기본 개체 참조 변수에 대한 원자 연산을 지원합니다. 휘발성 변수에 대한 읽기 및 쓰기처럼 작동하는 get 및 set 메서드가 있습니다. 즉, 세트는 동일한 변수에 대한 후속 get과 사전 발생 관계를 갖습니다. 원자 compareAndSet 메서드에는 이러한 메모리 일관성 기능도 있습니다.

AtomicReference 메서드

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

Sr. 아니. 방법 및 설명
1

public boolean compareAndSet(V expect, V update)

현재 값 == 예상 값인 경우 값을 지정된 업데이트 된 값으로 원자 적으로 설정합니다.

2

public boolean get()

현재 값을 반환합니다.

public boolean getAndSet(V newValue)

원자 적으로 주어진 값으로 설정하고 이전 값을 반환합니다.

4

public void lazySet(V newValue)

결국 주어진 값으로 설정됩니다.

5

public void set(V newValue)

주어진 값으로 무조건 설정합니다.

6

public String toString()

현재 값의 문자열 표현을 반환합니다.

7

public boolean weakCompareAndSet(V expect, V update)

현재 값 == 예상 값인 경우 값을 지정된 업데이트 된 값으로 원자 적으로 설정합니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 AtomicReference 변수의 사용법을 보여줍니다.

import java.util.concurrent.atomic.AtomicReference;

public class TestThread {
   private static String message = "hello";
   private static AtomicReference<String> atomicReference;

   public static void main(final String[] arguments) throws InterruptedException {
      atomicReference = new AtomicReference<String>(message);
      
      new Thread("Thread 1") {
         
         public void run() {
            atomicReference.compareAndSet(message, "Thread 1");
            message = message.concat("-Thread 1!");
         };
      }.start();

      System.out.println("Message is: " + message);
      System.out.println("Atomic Reference of Message is: " + atomicReference.get());
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Message is: hello
Atomic Reference of Message is: Thread 1

java.util.concurrent.atomic.AtomicIntegerArray 클래스는 원자 적으로 읽고 쓸 수있는 기본 int 배열에 대한 작업을 제공하며 고급 원자 작업도 포함합니다. AtomicIntegerArray는 기본 int 배열 변수에 대한 원자 연산을 지원합니다. 휘발성 변수에 대한 읽기 및 쓰기처럼 작동하는 get 및 set 메서드가 있습니다. 즉, 세트는 동일한 변수에 대한 후속 get과 사전 발생 관계를 갖습니다. 원자 compareAndSet 메서드에는 이러한 메모리 일관성 기능도 있습니다.

AtomicIntegerArray 메서드

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

Sr. 아니. 방법 및 설명
1

public int addAndGet(int i, int delta)

인덱스 i의 요소에 주어진 값을 원자 적으로 추가합니다.

2

public boolean compareAndSet(int i, int expect, int update)

현재 값 == 예상 값인 경우 위치 i의 요소를 지정된 업데이트 된 값으로 원자 적으로 설정합니다.

public int decrementAndGet(int i)

인덱스 i의 요소를 원자 적으로 1 씩 감소시킵니다.

4

public int get(int i)

위치 i에서 현재 값을 가져옵니다.

5

public int getAndAdd(int i, int delta)

인덱스 i의 요소에 주어진 값을 원자 적으로 추가합니다.

6

public int getAndDecrement(int i)

인덱스 i의 요소를 원자 적으로 1 씩 감소시킵니다.

7

public int getAndIncrement(int i)

인덱스 i의 요소를 원자 적으로 1 씩 증가시킵니다.

8

public int getAndSet(int i, int newValue)

i 위치의 요소를 주어진 값으로 원자 적으로 설정하고 이전 값을 반환합니다.

9

public int incrementAndGet(int i)

인덱스 i의 요소를 원자 적으로 1 씩 증가시킵니다.

10

public void lazySet(int i, int newValue)

결국 i 위치의 요소를 주어진 값으로 설정합니다.

11

public int length()

배열의 길이를 반환합니다.

12

public void set(int i, int newValue)

i 위치의 요소를 주어진 값으로 설정합니다.

13

public String toString()

배열의 현재 값에 대한 문자열 표현을 반환합니다.

14

public boolean weakCompareAndSet(int i, int expect, int update)

현재 값 == 예상 값인 경우 위치 i의 요소를 지정된 업데이트 된 값으로 원자 적으로 설정합니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 AtomicIntegerArray 변수의 사용법을 보여줍니다.

import java.util.concurrent.atomic.AtomicIntegerArray;

public class TestThread {
   private static AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(10);

   public static void main(final String[] arguments) throws InterruptedException {
      
      for (int i = 0; i<atomicIntegerArray.length(); i++) {
         atomicIntegerArray.set(i, 1);
      }

      Thread t1 = new Thread(new Increment());
      Thread t2 = new Thread(new Compare());
      t1.start();
      t2.start();

      t1.join();
      t2.join();

      System.out.println("Values: ");

      for (int i = 0; i<atomicIntegerArray.length(); i++) {
         System.out.print(atomicIntegerArray.get(i) + " ");
      }
   }

   static class Increment implements Runnable {

      public void run() {

         for(int i = 0; i<atomicIntegerArray.length(); i++) {
            int add = atomicIntegerArray.incrementAndGet(i);
            System.out.println("Thread " + Thread.currentThread().getId() 
               + ", index " +i + ", value: "+ add);
         }
      }
   }

   static class Compare implements Runnable {

      public void run() {

         for(int i = 0; i<atomicIntegerArray.length(); i++) {
            boolean swapped = atomicIntegerArray.compareAndSet(i, 2, 3);
            
            if(swapped) {
               System.out.println("Thread " + Thread.currentThread().getId()
                  + ", index " +i + ", value: 3");
            }
         }
      }
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Thread 10, index 0, value: 2
Thread 10, index 1, value: 2
Thread 10, index 2, value: 2
Thread 11, index 0, value: 3
Thread 10, index 3, value: 2
Thread 11, index 1, value: 3
Thread 11, index 2, value: 3
Thread 10, index 4, value: 2
Thread 11, index 3, value: 3
Thread 10, index 5, value: 2
Thread 10, index 6, value: 2
Thread 11, index 4, value: 3
Thread 10, index 7, value: 2
Thread 11, index 5, value: 3
Thread 10, index 8, value: 2
Thread 11, index 6, value: 3
Thread 10, index 9, value: 2
Thread 11, index 7, value: 3
Thread 11, index 8, value: 3
Thread 11, index 9, value: 3
Values:
3 3 3 3 3 3 3 3 3 3

java.util.concurrent.atomic.AtomicLongArray 클래스는 원자 적으로 읽고 쓸 수있는 기본 long 배열에 대한 작업을 제공하며 고급 원자 작업도 포함합니다. AtomicLongArray는 기본 long 배열 변수에 대한 원자 연산을 지원합니다. 휘발성 변수에 대한 읽기 및 쓰기처럼 작동하는 get 및 set 메서드가 있습니다. 즉, 세트는 동일한 변수에 대한 후속 get과 사전 발생 관계를 갖습니다. 원자 compareAndSet 메서드에는 이러한 메모리 일관성 기능도 있습니다.

AtomicLongArray 메서드

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

Sr. 아니. 방법 및 설명
1

public long addAndGet(int i, long delta)

인덱스 i의 요소에 주어진 값을 원자 적으로 추가합니다.

2

public boolean compareAndSet(int i, long expect, long update)

현재 값 == 예상 값인 경우 위치 i의 요소를 지정된 업데이트 된 값으로 원자 적으로 설정합니다.

public long decrementAndGet(int i)

인덱스 i의 요소를 원자 적으로 1 씩 감소시킵니다.

4

public long get(int i)

위치 i에서 현재 값을 가져옵니다.

5

public long getAndAdd(int i, long delta)

인덱스 i의 요소에 주어진 값을 원자 적으로 추가합니다.

6

public long getAndDecrement(int i)

인덱스 i의 요소를 원자 적으로 1 씩 감소시킵니다.

7

public long getAndIncrement(int i)

인덱스 i의 요소를 원자 적으로 1 씩 증가시킵니다.

8

public long getAndSet(int i, long newValue)

i 위치의 요소를 주어진 값으로 원자 적으로 설정하고 이전 값을 반환합니다.

9

public long incrementAndGet(int i)

인덱스 i의 요소를 원자 적으로 1 씩 증가시킵니다.

10

public void lazySet(int i, long newValue)

결국 i 위치의 요소를 주어진 값으로 설정합니다.

11

public int length()

배열의 길이를 반환합니다.

12

public void set(int i, long newValue)

i 위치의 요소를 주어진 값으로 설정합니다.

13

public String toString()

배열의 현재 값에 대한 문자열 표현을 반환합니다.

14

public boolean weakCompareAndSet(int i, long expect, long update)

현재 값 == 예상 값인 경우 위치 i의 요소를 지정된 업데이트 된 값으로 원자 적으로 설정합니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 AtomicIntegerArray 변수의 사용법을 보여줍니다.

import java.util.concurrent.atomic.AtomicLongArray;

public class TestThread {
   private static AtomicLongArray atomicLongArray = new AtomicLongArray(10);

   public static void main(final String[] arguments) throws InterruptedException {

      for (int i = 0; i<atomicLongArray.length(); i++) {
         atomicLongArray.set(i, 1);
      }

      Thread t1 = new Thread(new Increment());
      Thread t2 = new Thread(new Compare());
      t1.start();
      t2.start();

      t1.join();
      t2.join();

      System.out.println("Values: ");
      
      for (int i = 0; i<atomicLongArray.length(); i++) {
         System.out.print(atomicLongArray.get(i) + " ");
      }
   }  

   static class Increment implements Runnable {

      public void run() {

         for(int i = 0; i<atomicLongArray.length(); i++) {
            long add = atomicLongArray.incrementAndGet(i);
            System.out.println("Thread " + Thread.currentThread().getId() 
               + ", index " +i + ", value: "+ add);
         }
      }
   }

   static class Compare implements Runnable {

      public void run() {

         for(int i = 0; i<atomicLongArray.length(); i++) {
            boolean swapped = atomicLongArray.compareAndSet(i, 2, 3);
            
            if(swapped) {
               System.out.println("Thread " + Thread.currentThread().getId()
                  + ", index " +i + ", value: 3");
            }
         }
      }
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Thread 9, index 0, value: 2
Thread 10, index 0, value: 3
Thread 9, index 1, value: 2
Thread 9, index 2, value: 2
Thread 9, index 3, value: 2
Thread 9, index 4, value: 2
Thread 10, index 1, value: 3
Thread 9, index 5, value: 2
Thread 10, index 2, value: 3
Thread 9, index 6, value: 2
Thread 10, index 3, value: 3
Thread 9, index 7, value: 2
Thread 10, index 4, value: 3
Thread 9, index 8, value: 2
Thread 9, index 9, value: 2
Thread 10, index 5, value: 3
Thread 10, index 6, value: 3
Thread 10, index 7, value: 3
Thread 10, index 8, value: 3
Thread 10, index 9, value: 3
Values: 
3 3 3 3 3 3 3 3 3 3

java.util.concurrent.atomic.AtomicReferenceArray 클래스는 원자 적으로 읽고 쓸 수있는 기본 참조 배열에 대한 작업을 제공하며 고급 원자 작업도 포함합니다. AtomicReferenceArray는 기본 참조 배열 변수에 대한 원자 연산을 지원합니다. 휘발성 변수에 대한 읽기 및 쓰기처럼 작동하는 get 및 set 메서드가 있습니다. 즉, 세트는 동일한 변수에 대한 후속 get과 사전 발생 관계를 갖습니다. 원자 compareAndSet 메서드에는 이러한 메모리 일관성 기능도 있습니다.

AtomicReferenceArray 메서드

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

Sr. 아니. 방법 및 설명
1

public boolean compareAndSet(int i, E expect, E update)

현재 값 == 예상 값인 경우 위치 i의 요소를 지정된 업데이트 된 값으로 원자 적으로 설정합니다.

2

public E get(int i)

위치 i에서 현재 값을 가져옵니다.

public E getAndSet(int i, E newValue)

i 위치의 요소를 주어진 값으로 원자 적으로 설정하고 이전 값을 반환합니다.

4

public void lazySet(int i, E newValue)

결국 i 위치의 요소를 주어진 값으로 설정합니다.

5

public int length()

배열의 길이를 반환합니다.

6

public void set(int i, E newValue)

i 위치의 요소를 주어진 값으로 설정합니다.

7

public String toString()

배열의 현재 값에 대한 문자열 표현을 반환합니다.

8

public boolean weakCompareAndSet(int i, E expect, E update)

현재 값 == 예상 값인 경우 위치 i의 요소를 지정된 업데이트 된 값으로 원자 적으로 설정합니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 AtomicReferenceArray 변수의 사용법을 보여줍니다.

import java.util.concurrent.atomic.AtomicReferenceArray;

public class TestThread {
   private static String[] source = new String[10];
   private static AtomicReferenceArray<String> atomicReferenceArray 
      = new AtomicReferenceArray<String>(source);

   public static void main(final String[] arguments) throws InterruptedException {

      for (int i = 0; i<atomicReferenceArray.length(); i++) {
         atomicReferenceArray.set(i, "item-2");
      }

      Thread t1 = new Thread(new Increment());
      Thread t2 = new Thread(new Compare());
      t1.start();
      t2.start();

      t1.join();
      t2.join();		
   }  

   static class Increment implements Runnable {
      
      public void run() {
         
         for(int i = 0; i<atomicReferenceArray.length(); i++) {
            String add = atomicReferenceArray.getAndSet(i,"item-"+ (i+1));
            System.out.println("Thread " + Thread.currentThread().getId() 
               + ", index " +i + ", value: "+ add);
         }
      }
   }

   static class Compare implements Runnable {
      
      public void run() {
         
         for(int i = 0; i<atomicReferenceArray.length(); i++) {
            System.out.println("Thread " + Thread.currentThread().getId() 
               + ", index " +i + ", value: "+ atomicReferenceArray.get(i));
            boolean swapped = atomicReferenceArray.compareAndSet(i, "item-2", "updated-item-2");
            System.out.println("Item swapped: " + swapped);
            
            if(swapped) {
               System.out.println("Thread " + Thread.currentThread().getId() 
                  + ", index " +i + ", updated-item-2");
            }
         }
      }
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Thread 9, index 0, value: item-2
Thread 10, index 0, value: item-1
Item swapped: false
Thread 10, index 1, value: item-2
Item swapped: true
Thread 9, index 1, value: updated-item-2
Thread 10, index 1, updated-item-2
Thread 10, index 2, value: item-3
Item swapped: false
Thread 10, index 3, value: item-2
Item swapped: true
Thread 10, index 3, updated-item-2
Thread 10, index 4, value: item-2
Item swapped: true
Thread 10, index 4, updated-item-2
Thread 10, index 5, value: item-2
Item swapped: true
Thread 10, index 5, updated-item-2
Thread 10, index 6, value: item-2
Thread 9, index 2, value: item-2
Item swapped: true
Thread 9, index 3, value: updated-item-2
Thread 10, index 6, updated-item-2
Thread 10, index 7, value: item-2
Thread 9, index 4, value: updated-item-2
Item swapped: true
Thread 9, index 5, value: updated-item-2
Thread 10, index 7, updated-item-2
Thread 9, index 6, value: updated-item-2
Thread 10, index 8, value: item-2
Thread 9, index 7, value: updated-item-2
Item swapped: true
Thread 9, index 8, value: updated-item-2
Thread 10, index 8, updated-item-2
Thread 9, index 9, value: item-2
Thread 10, index 9, value: item-10
Item swapped: false

java.util.concurrent.Executor 인터페이스는 새 작업 시작을 지원하는 간단한 인터페이스입니다.

ExecutorService 메서드

Sr. 아니. 방법 및 설명
1

void execute(Runnable command)

나중에 주어진 명령을 실행합니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 Executor 인터페이스의 사용법을 보여줍니다.

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      Executor executor = Executors.newCachedThreadPool();
      executor.execute(new Task());
      ThreadPoolExecutor pool = (ThreadPoolExecutor)executor;
      pool.shutdown();
   }  

   static class Task implements Runnable {
      
      public void run() {
         
         try {
            Long duration = (long) (Math.random() * 5);
            System.out.println("Running Task!");
            TimeUnit.SECONDS.sleep(duration);
            System.out.println("Task Completed");
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Running Task!
Task Completed

java.util.concurrent.ExecutorService 인터페이스는 Executor 인터페이스의 하위 인터페이스이며 개별 작업과 실행기 자체의 수명주기를 관리하는 기능을 추가합니다.

ExecutorService 메서드

Sr. 아니. 방법 및 설명
1

boolean awaitTermination(long timeout, TimeUnit unit)

종료 요청 후 모든 작업이 실행을 완료하거나 시간 초과가 발생하거나 현재 스레드가 중단 될 때까지 차단합니다.

2

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)

주어진 작업을 실행하고 모든 완료시 상태와 결과를 보유한 Future 목록을 반환합니다.

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)

주어진 작업을 실행하고 모든 완료 또는 제한 시간이 만료 될 때 상태 및 결과를 보유한 Future 목록을 반환합니다.

4

<T> T invokeAny(Collection<? extends Callable<T>> tasks)

주어진 작업을 실행하고 성공적으로 완료된 작업의 결과를 반환합니다 (예 : 예외 발생없이).

5

<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)

주어진 시간 초과가 경과하기 전에 수행 한 작업이 있으면 성공적으로 완료된 (예 : 예외 발생없이) 작업의 결과를 반환하여 주어진 작업을 실행합니다.
6

boolean isShutdown()

이 실행 프로그램이 종료 된 경우 true를 반환합니다.

7

boolean isTerminated()

종료 후 모든 작업이 완료되면 true를 반환합니다.

8

void shutdown()

이전에 제출 된 작업이 실행되지만 새 작업은 수락되지 않는 순서대로 종료를 시작합니다.

9

List<Runnable> shutdownNow()

현재 실행중인 모든 작업을 중지하려고 시도하고 대기중인 작업의 처리를 중지하며 실행을 기다리고 있던 작업 목록을 반환합니다.

10

<T> Future<T> submit(Callable<T> task)

실행을 위해 값을 반환하는 작업을 제출하고 작업의 보류중인 결과를 나타내는 Future를 반환합니다.

11

Future<?> submit(Runnable task)

실행을 위해 실행 가능한 작업을 제출하고 해당 작업을 나타내는 Future를 반환합니다.

12

<T> Future<T> submit(Runnable task, T result)

실행을 위해 실행 가능한 작업을 제출하고 해당 작업을 나타내는 Future를 반환합니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 ExecutorService 인터페이스의 사용법을 보여줍니다.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      ExecutorService executor = Executors.newSingleThreadExecutor();

      try {
         executor.submit(new Task());
         System.out.println("Shutdown executor");
         executor.shutdown();
         executor.awaitTermination(5, TimeUnit.SECONDS);
      } catch (InterruptedException e) {
         System.err.println("tasks interrupted");
      } finally {

         if (!executor.isTerminated()) {
            System.err.println("cancel non-finished tasks");
         }
         executor.shutdownNow();
         System.out.println("shutdown finished");
      }
   }

   static class Task implements Runnable {
      
      public void run() {
         
         try {
            Long duration = (long) (Math.random() * 20);
            System.out.println("Running Task!");
            TimeUnit.SECONDS.sleep(duration);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }	   
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Shutdown executor
Running Task!
shutdown finished
cancel non-finished tasks
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:302)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:328)
	at TestThread$Task.run(TestThread.java:39)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439) at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
	at java.lang.Thread.run(Thread.java:662)

java.util.concurrent.ScheduledExecutorService 인터페이스는 ExecutorService 인터페이스의 하위 인터페이스이며 향후 및 / 또는주기적인 작업 실행을 지원합니다.

ScheduledExecutorService 메서드

Sr. 아니. 방법 및 설명
1

<V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit)

지정된 지연 후 활성화되는 ScheduledFuture를 만들고 실행합니다.

2

ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)

지정된 지연 후 활성화되는 원샷 작업을 생성하고 실행합니다.

ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)

지정된 초기 지연 후 먼저 활성화되고 이후에 지정된 기간에 활성화되는 주기적 작업을 생성하고 실행합니다. 즉, initialDelay 후 initialDelay + period, initialDelay + 2 * period 등으로 실행이 시작됩니다.

4

ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)

지정된 초기 지연 후 먼저 활성화되고 이후에 한 실행의 종료와 다음 실행의 시작 사이에 지정된 지연으로 활성화되는 주기적 작업을 생성하고 실행합니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 ScheduledExecutorService 인터페이스의 사용법을 보여줍니다.

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

      final ScheduledFuture<?> beepHandler = 
         scheduler.scheduleAtFixedRate(new BeepTask(), 2, 2, TimeUnit.SECONDS);

      scheduler.schedule(new Runnable() {

         @Override
         public void run() {
            beepHandler.cancel(true);
            scheduler.shutdown();			
         }
      }, 10, TimeUnit.SECONDS);
   }

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

그러면 다음과 같은 결과가 생성됩니다.

산출

beep
beep
beep
beep

고정 스레드 풀은 Executors 클래스의 정적 newFixedThreadPool () 메서드를 호출하여 얻을 수 있습니다.

통사론

ExecutorService fixedPool = Executors.newFixedThreadPool(2);

어디

  • 작업을 처리하기 위해 최대 2 개의 스레드가 활성화됩니다.

  • 2 개 이상의 스레드가 제출되면 스레드를 사용할 수있을 때까지 대기열에 보관됩니다.

  • 실행기의 실행 종료가 아직 호출되지 않은 경우 실패로 인해 스레드가 종료되는 경우 새 스레드가 생성됩니다.

  • 풀이 종료 될 때까지 모든 스레드가 존재합니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 newFixedThreadPool 메소드의 사용법을 보여줍니다.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThread {
	
   public static void main(final String[] arguments) throws InterruptedException {
      ExecutorService executor = Executors.newFixedThreadPool(2);

      // Cast the object to its class type
      ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;

      //Stats before tasks execution
      System.out.println("Largest executions: "
         + pool.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + pool.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + pool.getPoolSize());
      System.out.println("Currently executing threads: "
         + pool.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + pool.getTaskCount());

      executor.submit(new Task());
      executor.submit(new Task());

      //Stats after tasks execution
      System.out.println("Core threads: " + pool.getCorePoolSize());
      System.out.println("Largest executions: "
         + pool.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + pool.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + pool.getPoolSize());
      System.out.println("Currently executing threads: "
         + pool.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + pool.getTaskCount());

      executor.shutdown();
   }  

   static class Task implements Runnable {

      public void run() {
         
         try {
            Long duration = (long) (Math.random() * 5);
            System.out.println("Running Task! Thread Name: " +
               Thread.currentThread().getName());
               TimeUnit.SECONDS.sleep(duration);
            
            System.out.println("Task Completed! Thread Name: " +
               Thread.currentThread().getName());
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Largest executions: 0
Maximum allowed threads: 2
Current threads in pool: 0
Currently executing threads: 0
Total number of threads(ever scheduled): 0
Core threads: 2
Largest executions: 2
Maximum allowed threads: 2
Current threads in pool: 2
Currently executing threads: 1
Total number of threads(ever scheduled): 2
Running Task! Thread Name: pool-1-thread-1
Running Task! Thread Name: pool-1-thread-2
Task Completed! Thread Name: pool-1-thread-2
Task Completed! Thread Name: pool-1-thread-1

캐시 된 스레드 풀은 Executors 클래스의 정적 newCachedThreadPool () 메서드를 호출하여 얻을 수 있습니다.

통사론

ExecutorService executor = Executors.newCachedThreadPool();

어디

  • newCachedThreadPool 메서드는 확장 가능한 스레드 풀이있는 실행기를 만듭니다.

  • 이러한 실행기는 많은 단기 작업을 시작하는 응용 프로그램에 적합합니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 newCachedThreadPool 메소드의 사용법을 보여줍니다.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThread {
	
   public static void main(final String[] arguments) throws InterruptedException {
      ExecutorService executor = Executors.newCachedThreadPool();

      // Cast the object to its class type
      ThreadPoolExecutor pool = (ThreadPoolExecutor) executor;

      //Stats before tasks execution
      System.out.println("Largest executions: "
         + pool.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + pool.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + pool.getPoolSize());
      System.out.println("Currently executing threads: "
         + pool.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + pool.getTaskCount());

      executor.submit(new Task());
      executor.submit(new Task());

      //Stats after tasks execution
      System.out.println("Core threads: " + pool.getCorePoolSize());
      System.out.println("Largest executions: "
         + pool.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + pool.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + pool.getPoolSize());
      System.out.println("Currently executing threads: "
         + pool.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + pool.getTaskCount());

      executor.shutdown();
   }  

   static class Task implements Runnable {

      public void run() {
         
         try {
            Long duration = (long) (Math.random() * 5);
            System.out.println("Running Task! Thread Name: " +
               Thread.currentThread().getName());
               TimeUnit.SECONDS.sleep(duration);
            System.out.println("Task Completed! Thread Name: " +
               Thread.currentThread().getName());
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Largest executions: 0
Maximum allowed threads: 2147483647
Current threads in pool: 0
Currently executing threads: 0
Total number of threads(ever scheduled): 0
Core threads: 0
Largest executions: 2
Maximum allowed threads: 2147483647
Current threads in pool: 2
Currently executing threads: 2
Total number of threads(ever scheduled): 2
Running Task! Thread Name: pool-1-thread-1
Running Task! Thread Name: pool-1-thread-2
Task Completed! Thread Name: pool-1-thread-2
Task Completed! Thread Name: pool-1-thread-1

예약 된 스레드 풀은 Executors 클래스의 정적 newScheduledThreadPool () 메서드를 호출하여 얻을 수 있습니다.

통사론

ExecutorService executor = Executors.newScheduledThreadPool(1);

다음 TestThread 프로그램은 스레드 기반 환경에서 newScheduledThreadPool 메소드의 사용법을 보여줍니다.

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

      final ScheduledFuture<?> beepHandler = 
         scheduler.scheduleAtFixedRate(new BeepTask(), 2, 2, TimeUnit.SECONDS);

      scheduler.schedule(new Runnable() {

         @Override
         public void run() {
            beepHandler.cancel(true);
            scheduler.shutdown();			
         }
      }, 10, TimeUnit.SECONDS);
   }  

   static class BeepTask implements Runnable {

      public void run() {
         System.out.println("beep");      
      }
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

beep
beep
beep
beep

Executors 클래스의 정적 newSingleThreadExecutor () 메서드를 호출하여 단일 스레드 풀을 얻을 수 있습니다.

통사론

ExecutorService executor = Executors.newSingleThreadExecutor();

여기서 newSingleThreadExecutor 메서드는 한 번에 하나의 작업을 실행하는 실행기를 만듭니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 newSingleThreadExecutor 메소드의 사용법을 보여줍니다.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      ExecutorService executor = Executors.newSingleThreadExecutor();

      try {
         executor.submit(new Task());
         System.out.println("Shutdown executor");
         executor.shutdown();
         executor.awaitTermination(5, TimeUnit.SECONDS);
      } catch (InterruptedException e) {
         System.err.println("tasks interrupted");
      } finally {

         if (!executor.isTerminated()) {
            System.err.println("cancel non-finished tasks");
         }
         executor.shutdownNow();
         System.out.println("shutdown finished");
      }
   }

   static class Task implements Runnable {
      
      public void run() {

         try {
            Long duration = (long) (Math.random() * 20);
            System.out.println("Running Task!");
            TimeUnit.SECONDS.sleep(duration);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Shutdown executor
Running Task!
shutdown finished
cancel non-finished tasks
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:302)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:328)
	at TestThread$Task.run(TestThread.java:39) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) at java.util.concurrent.FutureTask.run(FutureTask.java:138) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
	at java.lang.Thread.run(Thread.java:662)

java.util.concurrent.ThreadPoolExecutor는 일반적으로 Executors 팩토리 메소드를 사용하여 구성된 여러 풀링 된 스레드 중 하나를 사용하여 제출 된 각 태스크를 실행하는 ExecutorService입니다. 또한 현재 스레드 통계를 확인하고 제어 할 수있는 다양한 유틸리티 메서드를 제공합니다.

ThreadPoolExecutor 메서드

Sr. 아니. 방법 및 설명
1

protected void afterExecute(Runnable r, Throwable t)

지정된 Runnable 실행 완료시 호출되는 메서드입니다.

2

void allowCoreThreadTimeOut(boolean value)

연결 유지 시간 내에 작업이 도착하지 않으면 코어 스레드가 시간 초과되고 종료 될 수 있는지 여부를 제어하는 ​​정책을 설정하고, 새 작업이 도착하면 필요한 경우 교체됩니다.

boolean allowsCoreThreadTimeOut()

이 풀이 keepAlive 시간 내에 작업이 도착하지 않으면 코어 스레드가 시간 초과되고 종료되도록 허용하는 경우 true를 반환하고, 새 작업이 도착할 때 필요한 경우 교체됩니다.

4

boolean awaitTermination(long timeout, TimeUnit unit)

종료 요청 후 모든 작업이 실행을 완료하거나 시간 초과가 발생하거나 현재 스레드가 중단 될 때까지 차단합니다.

5

protected void beforeExecute(Thread t, Runnable r)

지정된 스레드에서 지정된 Runnable을 실행하기 전에 호출 된 메서드입니다.

6

void execute(Runnable command)

미래에 주어진 작업을 실행합니다.

7

protected void finalize()

이 실행 프로그램이 더 이상 참조되지 않고 스레드가없는 경우 종료를 호출합니다.

8

int getActiveCount()

작업을 활발하게 실행중인 대략적인 스레드 수를 반환합니다.

9

long getCompletedTaskCount()

실행을 완료 한 대략적인 총 작업 수를 반환합니다.

10

int getCorePoolSize()

코어 스레드 수를 반환합니다.

11

long getKeepAliveTime(TimeUnit unit)

코어 풀 크기를 초과하는 스레드가 종료되기 전에 유휴 상태로 유지 될 수있는 시간 인 스레드 연결 유지 시간을 반환합니다.

12

int getLargestPoolSize()

풀에 동시에 있었던 가장 큰 스레드 수를 반환합니다.

13

int getMaximumPoolSize()

허용되는 최대 스레드 수를 반환합니다.

14

int getPoolSize()

풀의 현재 스레드 수를 반환합니다.

15

BlockingQueue getQueue()

이 실행자가 사용하는 태스크 큐를 리턴합니다.

15

RejectedExecutionHandler getRejectedExecutionHandler()

실행 불가능한 작업에 대한 현재 처리기를 반환합니다.

16

long getTaskCount()

실행이 예약 된 대략적인 총 작업 수를 반환합니다.

17

ThreadFactory getThreadFactory()

새 스레드를 만드는 데 사용되는 스레드 팩토리를 반환합니다.

18

boolean isShutdown()

이 실행 프로그램이 종료 된 경우 true를 반환합니다.

19

boolean isTerminated()

종료 후 모든 작업이 완료되면 true를 반환합니다.

20

boolean isTerminating()

이 실행 프로그램이 shutdown () 또는 shutdownNow () 후 종료하는 중이지만 완전히 종료되지 않은 경우 true를 반환합니다.

21

int prestartAllCoreThreads()

모든 코어 스레드를 시작하여 작업을 대기하도록합니다.

22

boolean prestartCoreThread()

코어 스레드를 시작하여 작업을 대기하도록합니다.

23

void purge()

취소 된 모든 Future 작업을 작업 대기열에서 제거하려고합니다.

24

boolean remove(Runnable task)

이 태스크가있는 경우 실행기의 내부 큐에서 제거하여 아직 시작되지 않은 경우 실행되지 않도록합니다.

25

void setCorePoolSize(int corePoolSize)

코어 스레드 수를 설정합니다.

26

void setKeepAliveTime(long time, TimeUnit unit)

스레드가 종료되기 전에 유휴 상태로 유지 될 수있는 시간 제한을 설정합니다.

27

void setMaximumPoolSize(int maximumPoolSize)

허용되는 최대 스레드 수를 설정합니다.

28

void setRejectedExecutionHandler(RejectedExecutionHandler handler)

실행 불가능한 작업에 대한 새 핸들러를 설정합니다.

29

void setThreadFactory(ThreadFactory threadFactory)

새 스레드를 만드는 데 사용되는 스레드 팩토리를 설정합니다.

30

void shutdown()

이전에 제출 된 작업이 실행되지만 새 작업은 수락되지 않는 순서대로 종료를 시작합니다.

31

List<Runnable> shutdownNow()

현재 실행중인 모든 작업을 중지하려고 시도하고 대기중인 작업의 처리를 중지하며 실행을 기다리고 있던 작업 목록을 반환합니다.

32

protected void terminated()

Executor가 종료되었을 때 호출되는 메서드입니다.

33

String toString()

실행 상태, 예상 작업자 및 작업 수의 표시를 포함하여이 풀과 해당 상태를 식별하는 문자열을 반환합니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 ThreadPoolExecutor 인터페이스의 사용법을 보여줍니다.

import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThread {
	
   public static void main(final String[] arguments) throws InterruptedException {
      ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newCachedThreadPool();

      //Stats before tasks execution
      System.out.println("Largest executions: "
         + executor.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + executor.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + executor.getPoolSize());
      System.out.println("Currently executing threads: "
         + executor.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + executor.getTaskCount());

      executor.submit(new Task());
      executor.submit(new Task());

      //Stats after tasks execution
      System.out.println("Core threads: " + executor.getCorePoolSize());
      System.out.println("Largest executions: "
         + executor.getLargestPoolSize());
      System.out.println("Maximum allowed threads: "
         + executor.getMaximumPoolSize());
      System.out.println("Current threads in pool: "
         + executor.getPoolSize());
      System.out.println("Currently executing threads: "
         + executor.getActiveCount());
      System.out.println("Total number of threads(ever scheduled): "
         + executor.getTaskCount());

      executor.shutdown();
   }  

   static class Task implements Runnable {

      public void run() {

         try {
            Long duration = (long) (Math.random() * 5);
            System.out.println("Running Task! Thread Name: " +
               Thread.currentThread().getName());
            TimeUnit.SECONDS.sleep(duration);
            System.out.println("Task Completed! Thread Name: " +
               Thread.currentThread().getName());
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Largest executions: 0
Maximum allowed threads: 2147483647
Current threads in pool: 0
Currently executing threads: 0
Total number of threads(ever scheduled): 0
Core threads: 0
Largest executions: 2
Maximum allowed threads: 2147483647
Current threads in pool: 2
Currently executing threads: 2
Total number of threads(ever scheduled): 2
Running Task! Thread Name: pool-1-thread-2
Running Task! Thread Name: pool-1-thread-1
Task Completed! Thread Name: pool-1-thread-1
Task Completed! Thread Name: pool-1-thread-2

java.util.concurrent.ScheduledThreadPoolExecutor는 ThreadPoolExecutor의 하위 클래스이며 지정된 지연 후 실행되거나 주기적으로 실행되도록 명령을 추가로 예약 할 수 있습니다.

ScheduledThreadPoolExecutor 메서드

Sr. 아니. 방법 및 설명
1

protected <V> RunnableScheduledFuture<V> decorateTask(Callable<V> callable, RunnableScheduledFuture<V> task)

콜 러블을 실행하는 데 사용되는 작업을 수정하거나 바꿉니다.

2

protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task)

실행 파일을 실행하는 데 사용되는 작업을 수정하거나 바꿉니다.

void execute(Runnable command)

필요한 지연없이 명령을 실행합니다.

4

boolean getContinueExistingPeriodicTasksAfterShutdownPolicy()

이 실행기가 종료 된 경우에도 기존의 주기적 작업을 계속 실행할지 여부에 대한 정책을 가져옵니다.

5

boolean getExecuteExistingDelayedTasksAfterShutdownPolicy()

이 실행기가 종료 된 경우에도 기존 지연된 작업을 실행할지 여부에 대한 정책을 가져옵니다.

6

BlockingQueue<Runnable> getQueue()

이 실행자가 사용하는 태스크 큐를 리턴합니다.

7

boolean getRemoveOnCancelPolicy()

취소시 취소 된 작업을 작업 대기열에서 즉시 제거해야하는지 여부에 대한 정책을 가져옵니다.

8

<V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit)

지정된 지연 후 활성화되는 ScheduledFuture를 만들고 실행합니다.

9

ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit)

지정된 지연 후 활성화되는 원샷 작업을 생성하고 실행합니다.

10

ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)

지정된 초기 지연 후 먼저 활성화되고 이후에 지정된 기간에 활성화되는 주기적 작업을 생성하고 실행합니다. 즉, initialDelay 후 initialDelay + period, initialDelay + 2 * period 등으로 실행이 시작됩니다.

11

ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)

지정된 초기 지연 후 먼저 활성화되고 이후에 한 실행의 종료와 다음 실행의 시작 사이에 지정된 지연으로 활성화되는 주기적 작업을 생성하고 실행합니다.

12

void setContinueExistingPeriodicTasksAfterShutdownPolicy (boolean value)

이 실행기가 종료 된 경우에도 기존의 정기 작업을 계속 실행할지 여부에 대한 정책을 설정합니다.

13

void setExecuteExistingDelayedTasksAfterShutdownPolicy (boolean value)

이 실행기가 종료 된 경우에도 기존 지연된 작업을 실행할지 여부에 대한 정책을 설정합니다.

14

void setRemoveOnCancelPolicy(boolean value)

취소시 작업 대기열에서 취소 된 작업을 즉시 제거할지 여부에 대한 정책을 설정합니다.

15

void shutdown()

이전에 제출 된 작업이 실행되지만 새 작업은 수락되지 않는 순서대로 종료를 시작합니다.

16

List<Runnable> shutdownNow()

현재 실행중인 모든 작업을 중지하려고 시도하고 대기중인 작업의 처리를 중지하며 실행을 기다리고 있던 작업 목록을 반환합니다.

17

<T> Future<T> submit(Callable<T> task)

실행을 위해 값을 반환하는 작업을 제출하고 작업의 보류중인 결과를 나타내는 Future를 반환합니다.

18

Future<?> submit(Runnable task)

실행을 위해 실행 가능한 작업을 제출하고 해당 작업을 나타내는 Future를 반환합니다.

19

<T> Future<T> submit(Runnable task, T result)

실행을 위해 실행 가능한 작업을 제출하고 해당 작업을 나타내는 Future를 반환합니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 ScheduledThreadPoolExecutor 인터페이스의 사용법을 보여줍니다.

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      final ScheduledThreadPoolExecutor scheduler = 
         (ScheduledThreadPoolExecutor)Executors.newScheduledThreadPool(1);

      final ScheduledFuture<?> beepHandler = 
         scheduler.scheduleAtFixedRate(new BeepTask(), 2, 2, TimeUnit.SECONDS);

      scheduler.schedule(new Runnable() {

         @Override
         public void run() {
            beepHandler.cancel(true);
            scheduler.shutdown();			
         }
      }, 10, TimeUnit.SECONDS);
   }  

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

그러면 다음과 같은 결과가 생성됩니다.

산출

beep
beep
beep
beep

java.util.concurrent.Callable 객체는 스레드 만 실행할 수있는 실행 가능한 인터페이스와 달리 스레드가 수행 한 계산 결과를 반환 할 수 있습니다. Callable 객체는 스레드에 의해 실행되는 작업의 진행 상황을 모니터링하는 메서드를 제공하는 Future 객체를 반환합니다. Future 객체를 사용하여 Callable의 상태를 확인한 다음 스레드가 완료되면 Callable에서 결과를 검색 할 수 있습니다. 시간 제한 기능도 제공합니다.

통사론

//submit the callable using ThreadExecutor
//and get the result as a Future object
Future<Long> result10 = executor.submit(new FactorialService(10));
 
//get the result using get method of the Future object
//get method waits till the thread execution and then return the result of the execution.
Long factorial10 = result10.get();

다음 TestThread 프로그램은 스레드 기반 환경에서 Futures와 Callables의 사용법을 보여줍니다.

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException,
      ExecutionException {

      ExecutorService executor = Executors.newSingleThreadExecutor();

      System.out.println("Factorial Service called for 10!");
      Future<Long> result10 = executor.submit(new FactorialService(10));

      System.out.println("Factorial Service called for 20!");
      Future<Long> result20 = executor.submit(new FactorialService(20));

      Long factorial10 = result10.get();
      System.out.println("10! = " + factorial10);

      Long factorial20 = result20.get();
      System.out.println("20! = " + factorial20);

      executor.shutdown();
   }  

   static class FactorialService implements Callable<Long> {
      private int number;

      public FactorialService(int number) {
         this.number = number;
      }

      @Override
      public Long call() throws Exception {
         return factorial();
      }

      private Long factorial() throws InterruptedException {
         long result = 1; 
         
         while (number != 0) { 
            result = number * result; 
            number--; 
            Thread.sleep(100); 
         }
         return result;	
      }
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Factorial Service called for 10!
Factorial Service called for 20!
10! = 3628800
20! = 2432902008176640000

fork-join 프레임 워크를 사용하면 여러 작업자에서 특정 작업을 중단 한 다음 결과가 결합 될 때까지 기다릴 수 있습니다. 다중 프로세서 시스템의 용량을 크게 활용합니다. 다음은 fork-join 프레임 워크에서 사용되는 핵심 개념과 객체입니다.

포크

Fork는 작업이 동시에 실행될 수있는 더 작고 독립적 인 하위 작업으로 분할되는 프로세스입니다.

통사론

Sum left  = new Sum(array, low, mid);
left.fork();

여기서 Sum은 RecursiveTask의 하위 클래스이며 left.fork ()는 작업을 하위 작업으로 분할합니다.

어울리다

조인은 하위 작업이 실행을 마치면 작업이 하위 작업의 모든 결과를 조인하고 그렇지 않으면 계속 대기하는 프로세스입니다.

통사론

left.join();

여기 왼쪽은 Sum 클래스의 객체입니다.

ForkJoinPool

fork-and-join 작업 분할과 함께 작동하도록 설계된 특수 스레드 풀입니다.

통사론

ForkJoinPool forkJoinPool = new ForkJoinPool(4);

여기에 4 CPU의 병렬 처리 수준을 가진 새로운 ForkJoinPool이 있습니다.

RecursiveAction

RecursiveAction은 값을 반환하지 않는 작업을 나타냅니다.

통사론

class Writer extends RecursiveAction {
   @Override
   protected void compute() { }
}

RecursiveTask

RecursiveTask는 값을 반환하는 작업을 나타냅니다.

통사론

class Sum extends RecursiveTask<Long> {
   @Override
   protected Long compute() { return null; }
}

다음 TestThread 프로그램은 스레드 기반 환경에서 Fork-Join 프레임 워크의 사용법을 보여줍니다.

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException, 
      ExecutionException {
      
      int nThreads = Runtime.getRuntime().availableProcessors();
      System.out.println(nThreads);
      
      int[] numbers = new int[1000]; 

      for(int i = 0; i < numbers.length; i++) {
         numbers[i] = i;
      }

      ForkJoinPool forkJoinPool = new ForkJoinPool(nThreads);
      Long result = forkJoinPool.invoke(new Sum(numbers,0,numbers.length));
      System.out.println(result);
   }  

   static class Sum extends RecursiveTask<Long> {
      int low;
      int high;
      int[] array;

      Sum(int[] array, int low, int high) {
         this.array = array;
         this.low   = low;
         this.high  = high;
      }

      protected Long compute() {
         
         if(high - low <= 10) {
            long sum = 0;
            
            for(int i = low; i < high; ++i) 
               sum += array[i];
               return sum;
         } else {	    	
            int mid = low + (high - low) / 2;
            Sum left  = new Sum(array, low, mid);
            Sum right = new Sum(array, mid, high);
            left.fork();
            long rightResult = right.compute();
            long leftResult  = left.join();
            return leftResult + rightResult;
         }
      }
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

32
499500

java.util.concurrent.BlockingQueue 인터페이스는 Queue 인터페이스의 하위 인터페이스이며 요소를 검색하기 전에 큐가 비어 있지 않을 때까지 대기하고 요소를 저장하기 전에 큐에서 공간을 사용할 수있을 때까지 대기하는 등의 작업을 추가로 지원합니다. .

BlockingQueue 메서드

Sr. 아니. 방법 및 설명
1

boolean add(E e)

용량 제한을 위반하지 않고 즉시 수행 할 수있는 경우 지정된 요소를이 큐에 삽입하고, 성공하면 true를 리턴하고 현재 사용 가능한 공간이 없으면 IllegalStateException을 발생시킵니다.

2

boolean contains(Object o)

이 큐에 지정된 요소가 포함 된 경우 true를 반환합니다.

int drainTo(Collection<? super E> c)

이 큐에서 사용 가능한 모든 요소를 ​​제거하고 지정된 컬렉션에 추가합니다.

4

int drainTo(Collection<? super E> c, int maxElements)

이 큐에서 사용 가능한 요소 수만큼 제거하고 지정된 컬렉션에 추가합니다.

5

boolean offer(E e)

용량 제한을 위반하지 않고 즉시 수행 할 수있는 경우 지정된 요소를이 큐에 삽입하고 성공하면 true를 반환하고 현재 사용 가능한 공간이 없으면 false를 반환합니다.

6

boolean offer(E e, long timeout, TimeUnit unit)

공간을 사용할 수있을 때까지 필요한 경우 지정된 대기 시간까지 대기하면서 지정된 요소를이 큐에 삽입합니다.

7

E poll(long timeout, TimeUnit unit)

요소를 사용할 수있을 때까지 필요한 경우 지정된 대기 시간까지 대기하면서이 큐의 헤드를 검색하고 제거합니다.

8

void put(E e)

지정된 요소를이 큐에 삽입하고 필요한 경우 공간을 사용할 수있을 때까지 기다립니다.

9

int remainingCapacity()

이 큐가 차단하지 않고 이상적으로 (메모리 또는 리소스 제약이없는 경우) 수용 할 수있는 추가 요소 수를 반환하거나 고유 한 제한이없는 경우 Integer.MAX_VALUE를 반환합니다.

10

boolean remove(Object o)

존재하는 경우이 큐에서 지정된 요소의 단일 인스턴스를 제거합니다.

11

E take()

필요한 경우 요소를 사용할 수있을 때까지 대기하면서이 큐의 헤드를 검색하고 제거합니다.

다음 TestThread 프로그램은 스레드 기반 환경에서 BlockingQueue 인터페이스의 사용법을 보여줍니다.

import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class TestThread {

   public static void main(final String[] arguments) throws InterruptedException {
      BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(10);

      Producer producer = new Producer(queue);
      Consumer consumer = new Consumer(queue);

      new Thread(producer).start();
      new Thread(consumer).start();

      Thread.sleep(4000);
   }  


   static class Producer implements Runnable {
      private BlockingQueue<Integer> queue;

      public Producer(BlockingQueue queue) {
         this.queue = queue;
      }

      @Override
      public void run() {
         Random random = new Random();

         try {
            int result = random.nextInt(100);
            Thread.sleep(1000);
            queue.put(result);
            System.out.println("Added: " + result);
            
            result = random.nextInt(100);
            Thread.sleep(1000);
            queue.put(result);
            System.out.println("Added: " + result);
            
            result = random.nextInt(100);
            Thread.sleep(1000);
            queue.put(result);
            System.out.println("Added: " + result);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }	   
   }

   static class Consumer implements Runnable {
      private BlockingQueue<Integer> queue;

      public Consumer(BlockingQueue queue) {
         this.queue = queue;
      }
      
      @Override
      public void run() {
         
         try {
            System.out.println("Removed: " + queue.take());
            System.out.println("Removed: " + queue.take());
            System.out.println("Removed: " + queue.take());
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Added: 52
Removed: 52
Added: 70
Removed: 70
Added: 27
Removed: 27

java.util.concurrent.ConcurrentMap 인터페이스는 Map 인터페이스의 하위 인터페이스이며 기본 맵 변수에 대한 원자 연산을 지원합니다. 휘발성 변수에 대한 읽기 및 쓰기처럼 작동하는 get 및 set 메서드가 있습니다. 즉, 세트는 동일한 변수에 대한 후속 get과 사전 발생 관계를 갖습니다. 이 인터페이스는 스레드 안전성과 원 자성 보장을 보장합니다.

ConcurrentMap 메서드

Sr. 아니. 방법 및 설명
1

default V compute(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)

지정된 키 및 현재 매핑 된 값 (또는 현재 매핑이없는 경우 null)에 대한 매핑 계산을 시도합니다.

2

default V computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)

지정된 키가 아직 값과 연관되지 않은 경우 (또는 null에 매핑 됨) 지정된 매핑 함수를 사용하여 해당 값을 계산하고 null이 아닌 경우이 맵에 입력합니다.

default V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)

지정된 키의 값이 있고 null이 아닌 경우 키와 현재 매핑 된 값이 주어지면 새 매핑을 계산합니다.

4

default void forEach(BiConsumer<? super K,? super V> action)

모든 항목이 처리되거나 작업에서 예외가 발생할 때까지이 맵의 각 항목에 대해 지정된 작업을 수행합니다.

5

default V getOrDefault(Object key, V defaultValue)

지정된 키가 매핑되는 값을 반환하거나이 맵에 키에 대한 매핑이없는 경우 defaultValue를 반환합니다.

6

default V merge(K key, V value, BiFunction<? super V,? super V,? extends V> remappingFunction)

지정된 키가 아직 값과 연결되어 있지 않거나 null과 연결되어있는 경우 해당 키를 지정된 null이 아닌 값과 연결합니다.

7

V putIfAbsent(K key, V value)

지정된 키가 아직 값과 연결되지 않은 경우 지정된 값과 연결합니다.

8

boolean remove(Object key, Object value)

현재 주어진 값에 매핑 된 경우에만 키 항목을 제거합니다.

9

V replace(K key, V value)

현재 일부 값에 매핑 된 경우에만 키 항목을 바꿉니다.

10

boolean replace(K key, V oldValue, V newValue)

현재 지정된 값에 매핑 된 경우에만 키 항목을 바꿉니다.

11

default void replaceAll(BiFunction<? super K,? super V,? extends V> function)

모든 항목이 처리되거나 함수에서 예외가 발생할 때까지 각 항목의 값을 해당 항목에 대해 지정된 함수를 호출 한 결과로 바꿉니다.

다음 TestThread 프로그램은 ConcurrentMap 대 HashMap의 사용법을 보여줍니다.

import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class TestThread {

   public static void main(final String[] arguments) {
      Map<String,String> map = new ConcurrentHashMap<String, String>();

      map.put("1", "One");
      map.put("2", "Two");
      map.put("3", "Three");
      map.put("5", "Five");
      map.put("6", "Six");

      System.out.println("Initial ConcurrentHashMap: " + map);
      Iterator<String> iterator = map.keySet().iterator();

      try { 
         
         while(iterator.hasNext()) {
            String key = iterator.next();
            
            if(key.equals("3")) {
               map.put("4", "Four");
            }
         }
      } catch(ConcurrentModificationException cme) {
         cme.printStackTrace();
      }
      System.out.println("ConcurrentHashMap after modification: " + map);

      map = new HashMap<String, String>();

      map.put("1", "One");
      map.put("2", "Two");
      map.put("3", "Three");
      map.put("5", "Five");
      map.put("6", "Six");

      System.out.println("Initial HashMap: " + map);
      iterator = map.keySet().iterator();

      try {
         
         while(iterator.hasNext()) {
            String key = iterator.next();
            
            if(key.equals("3")) {
               map.put("4", "Four");
            }
         }
         System.out.println("HashMap after modification: " + map);
      } catch(ConcurrentModificationException cme) {
         cme.printStackTrace();
      }
   }  
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Initial ConcurrentHashMap: {1 = One, 2 = Two, 3 = Three, 5 = Five, 6 = Six}
ConcurrentHashMap after modification: {1 = One, 2 = Two, 3 = Three, 4 = Four, 5 = Five, 6 = Six}
Initial HashMap: {1 = One, 2 = Two, 3 = Three, 5 = Five, 6 = Six}
java.util.ConcurrentModificationException
	at java.util.HashMap$HashIterator.nextNode(Unknown Source)
	at java.util.HashMap$KeyIterator.next(Unknown Source)
	at TestThread.main(TestThread.java:48)

java.util.concurrent.ConcurrentNavigableMap 인터페이스는 ConcurrentMap 인터페이스의 하위 인터페이스이며 NavigableMap 작업을 지원하며 탐색 가능한 하위 맵 및 대략적인 일치에 대해 반복적으로 지원합니다.

ConcurrentMap 메서드

Sr. 아니. 방법 및 설명
1

NavigableSet<K> descendingKeySet()

이 맵에 포함 된 키의 역순 NavigableSet 뷰를 반환합니다.

2

ConcurrentNavigableMap<K,V> descendingMap()

이지도에 포함 된 매핑의 역순보기를 반환합니다.

ConcurrentNavigableMap<K,V> headMap(K toKey)

이 맵의 키가 toKey보다 작은 부분의 뷰를 반환합니다.

4

ConcurrentNavigableMap<K,V> headMap(K toKey, boolean inclusive)

이 맵에서 키가 toKey보다 작거나 같은 경우 (포함이 true 인 경우) 부분의 뷰를 반환합니다.

5

NavigableSet<K> keySet()

이 맵에 포함 된 키의 NavigableSet 뷰를 반환합니다.

6

NavigableSet<K> navigableKeySet()

이 맵에 포함 된 키의 NavigableSet 뷰를 반환합니다.

7

ConcurrentNavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)

키 범위가 fromKey에서 toKey 인이 맵 부분의 뷰를 반환합니다.

8

ConcurrentNavigableMap<K,V> subMap(K fromKey, K toKey)

키 범위가 fromKey (포함)에서 toKey (배타)까지 인이 맵 부분의 뷰를 반환합니다.

9

ConcurrentNavigableMap<K,V> tailMap(K fromKey)

키가 fromKey보다 크거나 같은이 맵 부분의 뷰를 리턴합니다.

10

ConcurrentNavigableMap<K,V> tailMap(K fromKey, boolean inclusive)

이 맵에서 키가 fromKey보다 크거나 같은 경우 (포함이 true 인 경우 같음) 부분의 뷰를 반환합니다.

다음 TestThread 프로그램은 ConcurrentNavigableMap의 사용법을 보여줍니다.

import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;

public class TestThread {

   public static void main(final String[] arguments) {
      ConcurrentNavigableMap<String,String> map =
         new ConcurrentSkipListMap<String, String>();

      map.put("1", "One");
      map.put("2", "Two");
      map.put("3", "Three");
      map.put("5", "Five");
      map.put("6", "Six");

      System.out.println("Initial ConcurrentHashMap: "+map);
      System.out.println("HeadMap(\"2\") of ConcurrentHashMap: "+map.headMap("2"));
      System.out.println("TailMap(\"2\") of ConcurrentHashMap: "+map.tailMap("2"));
      System.out.println(
         "SubMap(\"2\", \"4\") of ConcurrentHashMap: "+map.subMap("2","4"));
   }  
}

그러면 다음과 같은 결과가 생성됩니다.

산출

Initial ConcurrentHashMap: {1 = One, 2 = Two, 3 = Three, 5 = Five, 6 = Six}
HeadMap("2") of ConcurrentHashMap: {1 = One}
TailMap("2") of ConcurrentHashMap: {2 = Two, 3 = Three, 5 = Five, 6 = Six}
SubMap("2", "4") of ConcurrentHashMap: {2 = Two, 3 = Three}