Java 스레드 통신 상세 정보

10318 단어 java라인통신
스레드 통신은 스레드의 조화로운 운행을 확보하는 데 사용되며, 일반적으로 스레드 동기화를 할 때에야 스레드 통신 문제를 고려해야 한다.
1. 전통적인 스레드 통신
일반적으로 Objeclt 클래스에서 제공하는 세 가지 방법:
  • wait () 는 현재 루틴을 기다리고 이 동기화 모니터의 잠금을 해제합니다. 다른 루틴이 동기화 모니터의 notify () 또는 notify All () 방법으로 루틴을 깨울 때까지..
  • notify (), 이 동기화 모니터에서 기다리는 라인을 깨우고, 여러 개가 있으면 임의로 깨우침을 선택합니다
  • notifyAll () 은 이 동기화 모니터에서 기다리는 모든 라인을 깨우쳐 줍니다. 이 라인들은 경쟁 자원을 스케줄링한 후 어떤 라인을 통해 이 동기화 모니터의 자물쇠를 가져와 실행할 수 있습니다
  • 이 세 가지 방법은 동기식 모니터 객체에서 호출해야 합니다.
    동기화 방법은 동기화 모니터가this 대상이기 때문에 이 세 가지 방법을 직접 호출할 수 있다.
    예는 다음과 같습니다.
    
    public class SyncMethodThreadCommunication {
      static class DataWrap{
        int data = 0;
        boolean flag = false;
        
        public synchronized void addThreadA(){
          if (flag) {
            try {
              wait();
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          } 
          
          data++;
          System.out.println(Thread.currentThread().getName() + " " + data);
          flag = true;
          notify();
        }
        
        public synchronized void addThreadB() {
          if (!flag) {
            try {
              wait();
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          } 
          
          data++;
          System.out.println(Thread.currentThread().getName() + " " + data);
          flag = false;
          notify();
        }
      }
      
      static class ThreadA extends Thread {
        private DataWrap data;
        
        public ThreadA(DataWrap dataWrap) {
          this.data = dataWrap;
        }
        
        @Override
        public void run() {
          for (int i = 0; i < 10; i++) {
            data.addThreadA();
          }
        }
      }
      
      static class ThreadB extends Thread {
        private DataWrap data;
        
        public ThreadB(DataWrap dataWrap) {
          this.data = dataWrap;
        }
        
        @Override
        public void run() {
          for (int i = 0; i < 10; i++) {
            data.addThreadB();
          }
        }
      }
      
      public static void main(String[] args) {
        // 
        DataWrap dataWrap = new DataWrap();
        
        new ThreadA(dataWrap).start();
        new ThreadB(dataWrap).start();
      }
    
    }
    
    
    코드 블록을 동기화할 때 모니터 대상을 사용하여 이 세 가지 방법을 호출해야 한다.
    예는 다음과 같습니다.
    
    public class SyncBlockThreadComminication {
      static class DataWrap{
        boolean flag;
        int data;
      }
      
      static class ThreadA extends Thread{
        DataWrap dataWrap;
        
        public ThreadA(DataWrap dataWrap){
          this.dataWrap = dataWrap;
        }
        
        @Override
        public void run() {
          for(int i = 0 ; i < 10; i++) {
            synchronized (dataWrap) {
              if (dataWrap.flag) {
                try {
                  dataWrap.wait();
                } catch (InterruptedException e) {
                  e.printStackTrace();
                }
              }
              
              dataWrap.data++;
              System.out.println(getName() + " " + dataWrap.data);
              dataWrap.flag = true;
              dataWrap.notify();
            }  
          }
        }
      }
      
      static class ThreadB extends Thread{
        DataWrap dataWrap;
        
        public ThreadB(DataWrap dataWrap){
          this.dataWrap = dataWrap;
        }
        
        @Override
        public void run() {
          for (int i = 0; i < 10; i++) {
              synchronized (dataWrap) {
                if (!dataWrap.flag) {
                  try {
                    dataWrap.wait();
                  } catch (InterruptedException e) {
                    e.printStackTrace();
                  }
                }
                
                dataWrap.data++;
                System.out.println(getName() + " " + dataWrap.data);
                dataWrap.flag = false;
                dataWrap.notify();
              }
            }  
          }
          
      }
      public static void main(String[] args) {
        // 
        
        DataWrap dataWrap = new DataWrap();
        new ThreadA(dataWrap).start();
        new ThreadB(dataWrap).start();
      }
    
    }
    
    
    2. Condition 제어 스레드 통신 사용
    Lock 객체를 사용하여 동기화를 보장하는 경우 Condition 객체를 사용하여 조정이 보장됩니다.
    예는 다음과 같습니다.
    
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    import com.sun.media.sound.RIFFInvalidDataException;
    
    import javafx.scene.chart.PieChart.Data;
    
    public class SyncLockThreadCommunication {
      static class DataWrap {
        int data;
        boolean flag;
        
        private final Lock lock = new ReentrantLock();
        private final Condition condition = lock.newCondition();
        
        public void addThreadA() {
          lock.lock();
          try {
            if (flag) {
              try {
                condition.await();
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }
            
            data++;
            System.out.println(Thread.currentThread().getName() + " " + data);
            flag = true;
            condition.signal();
          } finally {
            lock.unlock();
          }
        }
        
        public void addThreadB() {
          lock.lock();
          try {
            if (!flag) {
              try {
                condition.await();
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }
            
            data++;
            System.out.println(Thread.currentThread().getName() + " " + data);
            flag = false;
            condition.signal();
          } finally {
            lock.unlock();
          }
        }
      }
      
      static class ThreadA extends Thread{
        DataWrap dataWrap;
        
        public ThreadA(DataWrap dataWrap) {
          this.dataWrap = dataWrap;
        }
        
        @Override
        public void run() {
          for (int i = 0; i < 10; i++) {
            dataWrap.addThreadA();
          }
        }
      }
      
      static class ThreadB extends Thread{
        DataWrap dataWrap;
        
        public ThreadB(DataWrap dataWrap) {
          this.dataWrap = dataWrap;
        }
        
        @Override
        public void run() {
          for (int i = 0; i < 10; i++) {
            dataWrap.addThreadB();
          }
        }
      }
      
      public static void main(String[] args) {
        // 
        
        DataWrap dataWrap = new DataWrap();
        new ThreadA(dataWrap).start();
        new ThreadB(dataWrap).start();
      }
    
    }
    
    
    그 중에서 Condition 대상의await(),singal(),singalAll()은 각각wait(), notify()와 notifyAll() 방법에 대응한다.
    3. 차단 대기열 BlockingQueue를 사용하여 스레드 통신 제어
    BlockingQueue는Queue 인터페이스의 하위 인터페이스로 주로 스레드 통신에 사용되는데 이것은 하나의 특징을 가지고 있다. 생산자의 스레드가 BlockingQueue에 요소를 넣으려고 할 때 대기열이 가득 차면 이 스레드가 막힌다.소비자 스레드가 BlockingQueue에서 요소를 꺼내려고 할 때 대기열이 비어 있으면 이 스레드가 막힙니다.이 두 가지 특징은 각각 두 가지 차단 지원 방법,put(E)와 take()에 대응한다
    예는 다음과 같습니다.
    
    import java.util.concurrent.ArrayBlockingQueue;
    import java.util.concurrent.BlockingQueue;
    
    public class BlockingQueueThreadComminication {
      static class DataWrap{
        int data;
      }
      
      static class ThreadA extends Thread{
        private BlockingQueue<DataWrap> blockingQueue;
        
        public ThreadA(BlockingQueue<DataWrap> blockingQueue, String name) {
          super(name);
          this.blockingQueue = blockingQueue;
        }
        
        @Override
        public void run() {
          for (int i = 0; i < 100; i++) {
            try {
              DataWrap dataWrap = blockingQueue.take();
              
              dataWrap.data++;
              System.out.println(getName() + " " + dataWrap.data);
              sleep(1000);
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          }
        }
      }
      
      static class ThreadB extends Thread{
        private BlockingQueue<DataWrap> blockingQueue;
        private DataWrap dataWrap;
        
        public ThreadB(BlockingQueue<DataWrap> blockingQueue, DataWrap dataWrap, String name) {
          super(name);
          this.blockingQueue = blockingQueue;
          this.dataWrap = dataWrap;
        }
        
        @Override
        public void run() {
          for (int i = 0; i < 100; i++) {
            try {
              dataWrap.data++;
              System.out.println(getName() + " " + dataWrap.data);
              blockingQueue.put(dataWrap);
              sleep(1000);
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          }
        }
      }
      
      public static void main(String[] args) {
        /// 
        
        DataWrap dataWrap = new DataWrap();
        BlockingQueue<DataWrap> blockingQueue = new ArrayBlockingQueue<>(1);
        
        new ThreadA(blockingQueue, "Consumer").start();
        new ThreadB(blockingQueue, dataWrap, "Producer").start();
      }
    
    }
    
    
    BlockingQueue에는 다음과 같은 5가지 구현 클래스가 있습니다.
    ArrayBlockingQueue 배열 기반 BlockingQueue 대기열
    LinkedBlockingQueue 체인 테이블 기반 BlockingQueue 대기열
    Priority BlockingQueue에서 요소는 Comparable 인터페이스를 실현해야 합니다. 그 중에서 요소의 정렬은 Comparator에 따라 맞춤형 정렬됩니다.
    SynchronousQueue 동기화 대기열은 이 대기열에 대한 접근을 교체해야 합니다.
    DelayQueue 집합 요소는 Delay 인터페이스를 구현해야 합니다. 대기열의 요소 정렬은 Delay 인터페이스 방법인 getDelay () 의 반환값에 따라 정렬됩니다.
    이상은 본문의 전체 내용입니다. 여러분의 학습에 도움이 되고 저희를 많이 응원해 주십시오.

    좋은 웹페이지 즐겨찾기