스레드 동기화 및 통신 메커니즘

4028 단어
스레드 동기화
스레드 동기화는 다중 스레드가 경쟁 자원에 안전하게 접근하는 것을 확보하는 수단이다
스레드 간 통신
스레드 간에 왕왕 조율이 필요하고, 공동으로 어떤 업무를 완전하게 하며, 스레드 간의 상호 통신을 필요로 하며, 서로 다른 스레드 간의 상태를 통제해야 한다.
라인 동기화 및 통신 방식은 여러 가지가 있는데 본고는 흔히 볼 수 있는 두 가지 방식을 총괄하고자 한다.
  • synchronized,wait,notifysynchronized 방식은 가장 흔히 볼 수 있는 라인 동기화 방식이다.synchronized의 위치가 다르면 동기화 자물쇠의 대상이 다르기 때문에 서로 다른 쓰기 방법의 동기화 자물쇠 대상을 특별히 구분해야 한다.wait와 notify는synchronized와 함께 사용해야 하며, 라인 간의 통신을 실현해야 한다. 이것들은 모두 Object의 방법이지 Thread류의 방법이 아니다.wait 방법은 현재 라인이 막히고 동기화 자물쇠를 방출하며 cpu 사용권을 방출하고 동기화 자물쇠는 다른 라인에 의해 획득됩니다.한편, notify 방법은wait 방법을 호출하여 막힌 상태의 라인을 깨우고, 깨운 라인은 다시 동기화 자물쇠를 쟁취할 것이다.예: AB 3회 스레드 교체 인쇄
    private Runnable A = new Runnable() {
      public void run() {
          synchronized (lock) {
              while (countA > 0) {
                  System.out.println("A");
                  countA --;
                  lock.notify();
                  try {
                      lock.wait();
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
              lock.notify();
          }
      }
    };
    
    
    private Runnable B = new Runnable() {
      public void run() {
          synchronized (lock) {
              while (countB > 0) {
                  System.out.println("B");
                  countB --;
                  lock.notify();
                  try {
                      lock.wait();
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          }
      }
    };
    
  • ps: 마지막 순환에서 B가wait를 호출하여 막힌 상태에 들어갔기 때문에 A는 모든 코드를 실행하고 사망상태를 처리했다. 다른 라인이 B를 깨우지 않으면 B는 계속 막힌 상태에 있고 프로그램은 멈추지 않는다. 그러므로 A 내부 순환이 끝난 후에 B를 한 번 깨우면 프로그램은 순서대로 멈출 수 있다.
  • Lock, Condition Lock은 위의 synchronized 작용과 유사하여 루틴 동기화 기능을 실현할 수 있고, Condition은 wait와 notify와 유사하여 루틴 간의 통신에 사용된다.Lock과 Condition은 더욱 직관적인 사용 방식인 Lock의 lock과 unLock 방법으로 동기화 자물쇠를 가져오고 동기화 자물쇠를 방출하는 기능을 실현한다.Condition의 await 및 signal 방법으로 스레드 대기 막힘과 스레드를 깨우는 기능을 실현합니다.Condition을 사용하려면 동기화 잠금을 가져와야 합니다. 그렇지 않으면 오류가 발생합니다.상례와 같이 이런 방식으로 두 개의 라인 순서로 CD를 각각 세 번
  • 인쇄한다
      Lock lock2 = new ReentrantLock();
      Condition conditionC = lock2.newCondition();
      Condition conditionD = lock2.newCondition();
    
      private Runnable C = new Runnable() {
        public void run() {
            while (countC > 0) {
                lock2.lock();
                try{
                    System.out.println("C");
                    countC --;
                    try {
                        conditionD.signal();
                        conditionC.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }finally{
                    lock2.unlock();
                }
            }
            lock2.lock();
            conditionD.signal();
            lock2.unlock();
        }
      };
    
    private Runnable D = new Runnable() {
        public void run() {
            while (countD > 0) {
                lock2.lock();
                try{
                    System.out.println("D");
                    countD --;
                    try {
                        conditionC.signal();
                        conditionD.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }finally{
                    lock2.unlock();
                }
            }
        }
      };
    

    기타 스레드 동기화 방법
    스레드 동기화만 실현하는 데는 아직도 많은 방식이 있는데, 여기서 더 이상 자세하지 않고, 단지 간단하게 기록할 뿐이다
  • Semaphore semaphore = new Semaphore(3), Semaphore, 신호량, 현재 접근 자원의 스레드 개수를 제한할 수 있으며, 스레드가 동기화 자원에 접근할 때semaphore를 실행합니다.acquire (), 자원에 접근한 후semaphore를 실행합니다.release (), 동기화 잠금
  • ThreadLocal,ThreadLocal은 기이한 키 값이 맞다고 상상할 수 있지만 키의 키는 현재 호출된 스레드이다.ThreadLocal로 데이터를 저장할 수 있고 필요할 때 다시 꺼낼 수 있다.ThreadLocal이 저장한 데이터는 정확하고 동기화되지 않아 이상이 나타나지 않는다. 본질적으로 스레드 동기화를 실현하지 않았지만 실질적으로 스레드 동기화의 목적에 도달했다.
  • 원자량인 AtomicInteger, 원자량은 스레드가 안전한 용기와 유사하며 내부의 실현은 스레드가 안전하기 때문에 스레드 동기화 효과도 실현할 수 있다. 자주 사용하는 방법은 다음과 같다. AtomicInteger(int initialValue): 주어진 초기 값을 가진 새로운 AtomicInteger adddAddGet(int dalta)을 생성한다. 원자 방식으로 주어진 값을 현재 값과 get(): 현재 값을 획득
  • 좋은 웹페이지 즐겨찾기