Java 스레드 간 통신 방식 상세 정보

본고는 JAVA 다중 스레드 중의 스레드 간의 통신 방식에 대한 나의 이해를 요약하고 주로 코드와 문자를 결합하는 방식으로 스레드 간의 통신을 토론하기 때문에 책 중의 일부 예시 코드를 발췌하였는데 구체적인 내용은 다음과 같다.
① 동기화
여기서 말하는 동기화는 여러 개의 라인이synchronized 키워드를 통해 라인 간의 통신을 실현하는 것을 가리킨다.
참조 예:

public class MyObject {

 synchronized public void methodA() {
  //do something....
 }

 synchronized public void methodB() {
  //do some other thing
 }
}

public class ThreadA extends Thread {

 private MyObject object;
// 
 @Override
 public void run() {
  super.run();
  object.methodA();
 }
}

public class ThreadB extends Thread {

 private MyObject object;
// 
 @Override
 public void run() {
  super.run();
  object.methodB();
 }
}

public class Run {
 public static void main(String[] args) {
  MyObject object = new MyObject();

  // A B  :object
  ThreadA a = new ThreadA(object);
  ThreadB b = new ThreadB(object);
  a.start();
  b.start();
 }
}
스레드 A와 스레드 B는 같은 MyObject 클래스의 대상인object를 가지고 있기 때문에 이 두 스레드는 서로 다른 방법을 호출해야 하지만, 그것들은 동시에 실행된다. 예를 들어 스레드 B는 스레드 A가methodA() 방법을 실행한 후에methodB() 방법을 실행할 수 있다.이렇게 하면 스레드 A와 스레드 B가 통신을 실현할 수 있다.
이런 방식은 본질적으로'공유 메모리'식의 통신이다.여러 개의 루틴은 같은 공유 변수에 접근해야 하며, 자물쇠를 얻은 사람이 실행할 수 있다.
② while 폴링 방식
코드는 다음과 같습니다.

import java.util.ArrayList;
import java.util.List;

public class MyList {

 private List<String> list = new ArrayList<String>();
 public void add() {
  list.add("elements");
 }
 public int size() {
  return list.size();
 }
}

import mylist.MyList;

public class ThreadA extends Thread {

 private MyList list;

 public ThreadA(MyList list) {
  super();
  this.list = list;
 }

 @Override
 public void run() {
  try {
   for (int i = 0; i < 10; i++) {
    list.add();
    System.out.println(" " + (i + 1) + " ");
    Thread.sleep(1000);
   }
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }
}

import mylist.MyList;

public class ThreadB extends Thread {

 private MyList list;

 public ThreadB(MyList list) {
  super();
  this.list = list;
 }

 @Override
 public void run() {
  try {
   while (true) {
    if (list.size() == 5) {
     System.out.println("==5,  b ");
     throw new InterruptedException();
    }
   }
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }
}

import mylist.MyList;
import extthread.ThreadA;
import extthread.ThreadB;

public class Test {

 public static void main(String[] args) {
  MyList service = new MyList();

  ThreadA a = new ThreadA(service);
  a.setName("A");
  a.start();

  ThreadB b = new ThreadB(service);
  b.setName("B");
  b.start();
 }
}
이런 방식으로 스레드 A는 끊임없이 조건을 바꾸고, 스레드ThreadB는 끊임없이 while 문장을 통해 이 조건(list.size()=5)의 성립 여부를 검사하여 스레드 간의 통신을 실현했다.그러나 이런 방식은 CPU 자원을 낭비할 수 있다.자원을 낭비하는 이유는 JVM 스케줄러가 CPU를 스레드 B에 넘겨 실행할 때 유용한 작업은 하지 않고 조건이 성립되었는지 끊임없이 테스트하기 때문이다.마치 현실에서 누군가가 핸드폰 화면에 전화가 왔는지 안 왔는지 계속 보고 있는 것과 같다. 다른 일을 하고 있는데 전화가 왔을 때 벨을 울리면 전화가 왔음을 알리는 것이다.루틴에 대한 윤문의 영향은 참고할 수 있습니다Java의 스레드가 다운사이클을 수행하면 어떤 결과가 발생합니까
③ wait/notify 메커니즘
코드는 다음과 같습니다.

import java.util.ArrayList;
import java.util.List;

public class MyList {

 private static List<String> list = new ArrayList<String>();

 public static void add() {
  list.add("anyString");
 }

 public static int size() {
  return list.size();
 }
}


public class ThreadA extends Thread {

 private Object lock;

 public ThreadA(Object lock) {
  super();
  this.lock = lock;
 }

 @Override
 public void run() {
  try {
   synchronized (lock) {
    if (MyList.size() != 5) {
     System.out.println("wait begin "
       + System.currentTimeMillis());
     lock.wait();
     System.out.println("wait end "
       + System.currentTimeMillis());
    }
   }
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }
}


public class ThreadB extends Thread {
 private Object lock;

 public ThreadB(Object lock) {
  super();
  this.lock = lock;
 }

 @Override
 public void run() {
  try {
   synchronized (lock) {
    for (int i = 0; i < 10; i++) {
     MyList.add();
     if (MyList.size() == 5) {
      lock.notify();
      System.out.println(" ");
     }
     System.out.println(" " + (i + 1) + " !");
     Thread.sleep(1000);
    }
   }
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }
}

public class Run {

 public static void main(String[] args) {

  try {
   Object lock = new Object();

   ThreadA a = new ThreadA(lock);
   a.start();

   Thread.sleep(50);

   ThreadB b = new ThreadB(lock);
   b.start();
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }
}

스레드 A는 조건이 충족될 때(list.size () = 5) 작업을 수행합니다.스레드 B는list에 요소를 추가하여list의size를 변경합니다.
A, B는 어떻게 통신합니까?즉, 라인 A가list를 어떻게 알았는지.사이즈 () 벌써 5인데?
Object 클래스의wait () 및 notify () 메서드가 사용됩니다.
조건이 충족되지 않으면 (list.size ()!=5), 스레드 A 호출wait()는 CPU를 포기하고 차단 상태로 들어갑니다. ---②while 폴링처럼 CPU를 사용하지 않음
조건이 충족되면 스레드 B는 notify () 알림 스레드 A를 호출합니다. 알림 스레드 A란 스레드 A를 깨우고 실행 가능한 상태로 만드는 것입니다.
이런 방식의 장점 중 하나는 CPU의 이용률이 높아졌다는 것이다.
그러나 단점도 있다. 예를 들어 스레드 B가 먼저 실행되고 한꺼번에 5개의 요소를 추가하고 notify () 를 호출하여 알림을 보냈는데 이때 스레드 A가 실행되었다.스레드 A가wait () 를 실행하고 호출할 때, 영원히 깨어날 수 없습니다.왜냐하면 라인 B가 이미 통지를 보냈기 때문에 이후에 더 이상 통지를 보내지 않을 것이다.이것은 알림이 너무 이르면 프로그램의 실행 논리를 혼란시킬 수 있다는 것을 설명한다.
이상은 본고의 전체 내용입니다. 여러분이 자바 프로그래밍을 배우는 데 도움이 되기를 바랍니다.

좋은 웹페이지 즐겨찾기