java 기초 강좌의 다선정 상세 및 간단한 실례

18056 단어 java다중 스레드
java 다중 스레드 상세 정보
이 문장에서 우리는 다선정에 관심을 갖는다.다중 스레드는 복잡한 화제로 많은 내용을 포함하고 있다. 이 글은 주로 스레드의 기본 속성, 어떻게 스레드를 만드는지, 스레드의 상태 전환과 스레드 통신에 주목한다.
루틴은 운영체제가 실행하는 기본 단위로 프로세스에 봉인되어 하나의 프로세스에 여러 개의 루틴을 포함할 수 있다.설령 우리가 수동으로 라인을 만들지 않더라도 프로세스는 기본 라인이 실행될 것이다.
JVM에 대해 말하자면, 우리가 단일 스레드를 작성하여 실행할 때, JVM에도 적어도 두 개의 스레드가 실행되고 있다. 하나는 우리가 만든 프로그램이고, 하나는 쓰레기 수거이다.
스레드 기본 정보
우리는 Thread를 통해currentThread () 메서드는 현재 스레드에 대한 정보를 가져와 수정합니다.
다음 코드를 살펴보겠습니다.

 
String name = Thread.currentThread().getName();
    int priority = Thread.currentThread().getPriority();
    String groupName = Thread.currentThread().getThreadGroup().getName();
    boolean isDaemon = Thread.currentThread().isDaemon();
    System.out.println("Thread Name:" + name);
    System.out.println("Priority:" + priority);
    System.out.println("Group Name:" + groupName);
    System.out.println("IsDaemon:" + isDaemon);
    
    Thread.currentThread().setName("Test");
    Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
    name = Thread.currentThread().getName();
    priority = Thread.currentThread().getPriority();
    groupName = Thread.currentThread().getThreadGroup().getName();
    isDaemon = Thread.currentThread().isDaemon();
    System.out.println("Thread Name:" + name);
    System.out.println("Priority:" + priority);
여기에 나열된 등록 정보는 다음과 같습니다.
  • GroupName, 모든 스레드는 기본적으로 하나의 스레드 그룹에 있습니다. 우리는 스레드 그룹을 현저하게 만들 수 있습니다. 하나의 스레드 그룹에도 하위 스레드 그룹을 포함할 수 있습니다. 이렇게 하면 스레드와 스레드 그룹은 하나의 트리 구조를 구성합니다
  • Name, 모든 스레드에 이름이 있습니다. 명시적으로 지정하지 않으면 이름에 대한 규칙은 "Thread-xx"입니다
  • Priority는 각 스레드에 대해 자신의 우선 순위가 있고 JVM은 우선 순위에 대한 처리 방식이 선점식이다.JVM에서 우선 순위가 높은 스레드를 발견하면 즉시 실행합니다.여러 우선 순위가 같은 스레드의 경우 JVM이 폴링 처리합니다.Java의 스레드 우선 순위는 1부터 10까지이며 기본값은 5입니다. Thread 클래스는 2개의 상수를 정의합니다. MIN_PRIORITY 및 MAX_PRIORITY는 가장 높은 우선 순위와 가장 낮은 우선 순위를 나타냅니다.
  • 우리는 다음 코드를 볼 수 있다. 이 코드는 두 개의 서로 다른 우선순위 라인을 정의한다.
    
     
    public static void priorityTest()
    {
      Thread thread1 = new Thread("low")
      {
        public void run()
        {
          for (int i = 0; i < 5; i++)
          {
            System.out.println("Thread 1 is running.");
          }
        }
      };
      
      Thread thread2 = new Thread("high")
      {
        public void run()
        {
          for (int i = 0; i < 5; i++)
          {
            System.out.println("Thread 2 is running.");
          }
        }
      };
      
      thread1.setPriority(Thread.MIN_PRIORITY);
      thread2.setPriority(Thread.MAX_PRIORITY);
      thread1.start();
      thread2.start();
    }
    운행 결과에서 알 수 있듯이 높은 우선순위 라인이 실행된 후에야 낮은 우선순위 라인이 실행된다.
    이 속성은 부자 라인의 관계를 제어하는 데 사용됩니다. 만약true로 설정하면 부모 라인이 끝난 후에 그 아래의 모든 하위 라인도 끝납니다. 반대로 하위 라인의 생명 주기는 부모 라인의 영향을 받지 않습니다.
    다음 예를 살펴보겠습니다.
    
    IsDaemon  
    public static void daemonTest()
    {
      Thread thread1 = new Thread("daemon")
      {
        public void run()
        {
          Thread subThread = new Thread("sub")
          {
            public void run()
            {
              for(int i = 0; i < 100; i++)
              {
                System.out.println("Sub Thread Running " + i);
              }
            }
          };
          subThread.setDaemon(true);
          subThread.start();
          System.out.println("Main Thread end.");
        }
      };
      
      thread1.start();
    }
    위 코드의 실행 결과,subThread를 삭제하고 있습니다.setDaemon(true);후자를 비교해 보면 후자의 운행 과정에서 서브루틴은 실행을 완성한 후에 끝날 것이고 전자에서 서브루틴은 곧 끝날 것이다.
    어떻게 라인을 만듭니까
    위의 내용은 모두 기본 스레드 중의 일부 정보를 보여 줍니다. 그러면 어떻게 스레드를 만들어야 합니까?Java에서 우리는 세 가지 방식으로 라인을 만들 수 있다.
    Java의 스레드는 Thread 클래스를 계승하거나 Runnable 인터페이스를 실현하는 것입니다.
    내부 클래스를 사용하여 스레드 만들기
    우리는 내부 클래스를 사용하여 라인을 만들 수 있습니다. 프로세스는Thread 형식의 변수를 설명하고 run 방법을 다시 쓰는 것입니다.예제 코드는 다음과 같습니다.
    
     
    public static void createThreadByNestClass()
    {
      Thread thread = new Thread()
      {
        public void run()
        {
          for (int i =0; i < 5; i++)
          {
            System.out.println("Thread " + Thread.currentThread().getName() + " is running.");
          }
          System.out.println("Thread " + Thread.currentThread().getName() + " is finished.");
        }
      };
      thread.start();
    }
    스레드 생성을 위해 Thread 상속
    우리는Thread에서 하나의 종류를 파생시켜run방법을 다시 쓸 수 있는데, 이런 방식은 위와 비슷하다.예제 코드는 다음과 같습니다.
    
     Thread 
    class MyThread extends Thread
    {
      public void run()
      {
        for (int i =0; i < 5; i++)
        {
          System.out.println("Thread " + Thread.currentThread().getName() + " is running.");
        }
        System.out.println("Thread " + Thread.currentThread().getName() + " is finished.");
      }
    }
    
    
    public static void createThreadBySubClass()
    {
      MyThread thread = new MyThread();
      thread.start();
    }
    루틴 생성을 위한 Runnable 인터페이스 구현
    우리는 클래스를 정의하여 Runnable 인터페이스를 실현하고 이 클래스의 실례를 Thread 변수 구조 함수를 구축하는 매개 변수로 삼을 수 있다.예제 코드는 다음과 같습니다.
    
     Runnable 
    class MyRunnable implements Runnable
    {
      public void run() 
      {
        for (int i =0; i < 5; i++)
        {
          System.out.println("Thread " + Thread.currentThread().getName() + " is running.");
        }
        System.out.println("Thread " + Thread.currentThread().getName() + " is finished.");
      }
    }
    
    
    public static void createThreadByRunnable()
    {
      MyRunnable runnable = new MyRunnable();
      Thread thread = new Thread(runnable);
      thread.start();
    }
    상술한 세 가지 방식은 모두 라인을 만들 수 있고 예시 코드에서 볼 때 라인이 실행하는 기능은 같다. 그러면 이 세 가지 창설 방식은 무엇이 다른가?
    이것은 Java의 다중 스레드 실행 모드와 관련된다. Java의 경우 다중 스레드가 실행될 때'다중 객체 다중 스레드'와'단일 객체 다중 스레드'의 차이가 있다.
  • 다중 대상 다중 스레드, 프로그램이 실행 과정에서 다중 스레드 대상을 만들고 각 대상에 하나의 스레드를 실행합니다..
  • 단일 대상 다중 스레드, 프로그램이 실행 과정에서 하나의 스레드 대상을 만들고 그 위에 여러 개의 스레드를 실행합니다..
  • 분명히 스레드 동기화와 스케줄링의 측면에서 볼 때, 다중 대상의 다중 스레드는 좀 간단해야 한다.상기 세 가지 스레드 생성 방식은 앞의 두 가지 모두 다중 대상 다중 스레드에 속하고, 세 번째는 다중 대상 다중 스레드를 사용할 수도 있고 단일 대상 단일 스레드를 사용할 수도 있다.
    다음 예제 코드를 살펴보겠습니다. Object가 사용됩니다.notify 방법, 이 방법은 대상의 라인을 깨울 수 있습니다.Object.notifyAll 메서드는 객체의 모든 스레드를 깨웁니다.
    
    notify 
    public class NotifySample {
      
      public static void main(String[] args) throws InterruptedException
      {
        notifyTest();
        notifyTest2();
        notifyTest3();
      }
      
      private static void notifyTest() throws InterruptedException
      {
        MyThread[] arrThreads = new MyThread[3];
        for (int i = 0; i < arrThreads.length; i++)
        {
          arrThreads[i] = new MyThread();
          arrThreads[i].id = i;
          arrThreads[i].setDaemon(true);
          arrThreads[i].start();
        }
        Thread.sleep(500);
        for (int i = 0; i < arrThreads.length; i++)
        {
          synchronized(arrThreads[i])
          {
            arrThreads[i].notify();
          }
        }
      }
      
      private static void notifyTest2() throws InterruptedException
      {
        MyRunner[] arrMyRunners = new MyRunner[3];
        Thread[] arrThreads = new Thread[3];
        for (int i = 0; i < arrThreads.length; i++)
        {
          arrMyRunners[i] = new MyRunner();
          arrMyRunners[i].id = i;
          arrThreads[i] = new Thread(arrMyRunners[i]);
          arrThreads[i].setDaemon(true);
          arrThreads[i].start();
        }
        Thread.sleep(500);
        for (int i = 0; i < arrMyRunners.length; i++)
        {
          synchronized(arrMyRunners[i])
          {
            arrMyRunners[i].notify();
          }
        }
      }
      
      private static void notifyTest3() throws InterruptedException
      {
        MyRunner runner = new MyRunner();
        Thread[] arrThreads = new Thread[3];
        for (int i = 0; i < arrThreads.length; i++)
        {
          arrThreads[i] = new Thread(runner);
          arrThreads[i].setDaemon(true);
          arrThreads[i].start();
        }
        Thread.sleep(500);
    
        synchronized(runner)
        {
          runner.notifyAll();
        }
      }
    }
    
    class MyThread extends Thread
    {
      public int id = 0;
      public void run()
      {
        System.out.println(" " + id + " 5 。");
        try
        {
          synchronized(this)
          {
            this.wait(5*60*1000);
          }
        }
        catch(InterruptedException ex)
        {
          ex.printStackTrace();
        }
        System.out.println(" " + id + " 。");
      }
    }
    
    class MyRunner implements Runnable
    {
      public int id = 0;
      public void run() 
      {
        System.out.println(" " + id + " 5 。");
        try
        {
          synchronized(this)
          {
            this.wait(5*60*1000);
          }
        }
        catch(InterruptedException ex)
        {
          ex.printStackTrace();
        }
        System.out.println(" " + id + " 。");
      }
      
    }
    예시 코드에서 notifyTest () 와 notifyTest2 () 는'다중 대상 다중 스레드'입니다. notifyTest2 () 의 스레드가 Runnable 인터페이스를 실현하지만, 그 안에 Thread 그룹을 정의할 때, 모든 요소는 새로운 Runnable 실례를 사용합니다.notifyTest3()는 "단일 대상 다중 스레드"에 속합니다. Runnable 실례만 정의했기 때문에 모든 스레드가 이 실례를 사용합니다.
    notifyAll 방법은 "단일 대상 다중 스레드"상황에 적용됩니다. 왜냐하면 notify 방법은 무작위로 대상의 한 스레드만 깨울 수 있기 때문입니다.
    스레드 상태 전환
    스레드에 대해 말하자면, 우리가 그것을 만들어서 스레드 운행이 끝날 때까지 이 과정에서 스레드의 상태는 다음과 같을 수 있다.
  • 생성: Thread 인스턴스가 있지만 CPU에 리소스와 타임슬라이스가 할당되어 있습니다
  • 준비: 라인은 실행에 필요한 모든 자원을 얻었습니다. CPU가 시간 스케줄링을 하기만 기다리십시오..
  • 실행: 스레드는 현재 CPU 타임라인에 있으며 관련 논리를 실행하고 있습니다
  • 휴면: 일반적으로 Thread를 호출합니다.sleep 후의 상태, 이때 라인은 여전히 운행에 필요한 각종 자원을 가지고 있지만, CPU에 의해 스케줄링되지 않습니다..
  • 종료: 일반적으로 Thread를 호출합니다.suspend 후의 상태는 휴면과 유사하여 CPU가 이 라인을 스케줄링하지 않습니다. 다른 것은 이 상태에서 라인은 모든 자원을 방출합니다..
  • 사망: 스레드 운행이 끝나거나 Thread가 호출되었습니다.stop 방법.
  • 다음은 스레드 상태 전환 방법을 보여 드리겠습니다. 우선 다음 방법을 사용합니다.
  • Thread() 또는 Thread(Runnable): 구조 스레드..
  • Thread.start: 라인 시작..
  • Thread.sleep: 라인을 휴면 상태로 전환합니다.
  • Thread.interrupt: 라인 실행 중단..
  • Thread.join: 어떤 노선이 끝날 때까지 기다립니다..
  • Thread.yield: CPU에 있는 실행 타임라인을 박탈하고 다음 스케줄링을 기다립니다
  • Object.wait: object의 모든 라인을 잠그고 notify 방법이 실행될 때까지..
  • Object.notify: 무작위로 Object의 1개 라인을 깨우는..
  • Object.notifyAll: Object의 모든 스레드를 깨웁니다.
  • 다음은 바로 시연 시간입니다!!!
    스레드 대기 및 깨우기
    여기에는 Object가 주로 사용됩니다.wait와 Object.notify 방법, 위의 notify 실례를 참고하십시오.주의해야 할 것은wait와 notify는 모두 같은 대상을 겨냥해야 한다는 것이다. 우리가 Runnable 인터페이스를 실현하는 방식으로 라인을 만들 때,Thread 대상이 아닌 Runnable 대상에서 이 두 가지 방법을 사용해야 한다.
    라인의 휴면과 깨우기
    
    Thread.sleep 
    public class SleepSample {
      
      public static void main(String[] args) throws InterruptedException
      {
        sleepTest();
      }
      
      private static void sleepTest() throws InterruptedException
      {
        Thread thread = new Thread()
        {
          public void run()
          {
            System.out.println("  " + Thread.currentThread().getName() + " 5 。");
            try
            {
              Thread.sleep(5*60*1000);
            }
            catch(InterruptedException ex)
            {
              System.out.println("  " + Thread.currentThread().getName() + " 。");
            }
            System.out.println("  " + Thread.currentThread().getName() + " 。");
          }
        };
        thread.setDaemon(true);
        thread.start();
        Thread.sleep(500);
        thread.interrupt();
      }
    
    }
    스레드는 휴면 중에 Thread를 사용할 수 있습니다.interrupt에서 깨우십시오. 이 때 라인은 Interrupted Exception을 던집니다.
    스레드의 종료
    스레드가 있지만.stop 방법이지만 이 방법은 추천하지 않습니다. 우리는 위의 휴면과 깨우는 메커니즘을 이용하여 라인이 Iterrupted Exception을 처리할 때 라인을 끝낼 수 있습니다.
    
    Thread.interrupt 
    public class StopThreadSample {
    
      public static void main(String[] args) throws InterruptedException
      {
        stopTest();
      }
      
      private static void stopTest() throws InterruptedException
      {
        Thread thread = new Thread()
        {
          public void run()
          {
            System.out.println(" 。");
            try
            {
              Thread.sleep(1*60*1000);
            }
            catch(InterruptedException ex)
            {
              System.out.println(" , ");
              return;
            }
            System.out.println(" 。");
          }
        };
        thread.start();
        Thread.sleep(500);
        thread.interrupt();
      }
    }
    스레드의 동기화 대기
    우리가 메인 라인에서 10개의 하위 라인을 만들었고, 10개의 하위 라인이 모두 끝난 후에 메인 라인이 다음 논리를 실행하기를 기대한다면, 이 때 Thread를 사용해야 한다.조인이 등장했다.
    
    Thread.join 
    public class JoinSample {
    
      public static void main(String[] args) throws InterruptedException
      {
        joinTest();
      }
      
      private static void joinTest() throws InterruptedException
      {
        Thread thread = new Thread()
        {
          public void run()
          {
            try
            {
              for(int i = 0; i < 5; i++)
              {
                System.out.println(" 。");
                Thread.sleep(1000);
              }
            }
            catch(InterruptedException ex)
            {
              ex.printStackTrace();
            }
          }
        };
        thread.setDaemon(true);
        thread.start();
        Thread.sleep(1000);
        thread.join();
        System.out.println(" 。");
      }
    }
    우리는thread를 시도해 볼 수 있다.join();주석이나 삭제, 프로그램을 다시 실행하면 다른 것을 발견할 수 있습니다.
    스레드 간 통신
    우리는 하나의 프로세스 아래의 모든 스레드가 메모리 공간을 공유하는 것을 알고 있다. 그러면 우리는 어떻게 서로 다른 스레드 사이에서 정보를 전달합니까?Java I/O를 살펴보면서 PipedStream과 PipedReader에 대해 이야기했습니다. 여기가 바로 그 역할을 하는 곳입니다.
    다음 두 가지 예는 기능이 완전히 같다. 하나는 Stream을 사용하고 하나는 Reader/Writer를 사용한다.
    
    PipeInputStream/PipedOutpueStream  
    public static void communicationTest() throws IOException, InterruptedException
    {
      final PipedOutputStream pos = new PipedOutputStream();
      final PipedInputStream pis = new PipedInputStream(pos);
      
      Thread thread1 = new Thread()
      {
        public void run()
        {
          BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
          try
          {
            while(true)
            {
              String message = br.readLine();
              pos.write(message.getBytes());
              if (message.equals("end")) break;
            }
            br.close();
            pos.close();
          }
          catch(Exception ex)
          {
            ex.printStackTrace();
          }
        }
      };
      
      Thread thread2 = new Thread()
      {
        public void run()
        {
          byte[] buffer = new byte[1024];
          int bytesRead = 0;
          try
          {
            while((bytesRead = pis.read(buffer, 0, buffer.length)) != -1)
            {
              System.out.println(new String(buffer));
              if (new String(buffer).equals("end")) break;
              buffer = null;
              buffer = new byte[1024];
            }
            pis.close();
            buffer = null;
          }
          catch(Exception ex)
          {
            ex.printStackTrace();
          }
        }
      };
      
      thread1.setDaemon(true);
      thread2.setDaemon(true);
      thread1.start();
      thread2.start();
      thread1.join();
      thread2.join();
    }
    
    PipedReader/PipedWriter  
    private static void communicationTest2() throws InterruptedException, IOException
    {
      final PipedWriter pw = new PipedWriter();
      final PipedReader pr = new PipedReader(pw);
      final BufferedWriter bw = new BufferedWriter(pw);
      final BufferedReader br = new BufferedReader(pr);
      
      Thread thread1 = new Thread()
      {
        public void run()
        {
          
          BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
          try
          {
            while(true)
            {
              String message = br.readLine();
              bw.write(message);
              bw.newLine();
              bw.flush();
              if (message.equals("end")) break;
            }
            br.close();
            pw.close();
            bw.close();
          }
          catch(Exception ex)
          {
            ex.printStackTrace();
          }
        }
      };
      
      Thread thread2 = new Thread()
      {
        public void run()
        {
          
          String line = null;
          try
          {
            while((line = br.readLine()) != null)
            {
              System.out.println(line);
              if (line.equals("end")) break;
            }
            br.close();
            pr.close();
          }
          catch(Exception ex)
          {
            ex.printStackTrace();
          }
        }
      };
      
      thread1.setDaemon(true);
      thread2.setDaemon(true);
      thread1.start();
      thread2.start();
      thread1.join();
      thread2.join();
    }
    읽어주셔서 감사합니다. 여러분에게 도움이 되었으면 좋겠습니다. 본 사이트에 대한 지지에 감사드립니다!

    좋은 웹페이지 즐겨찾기