2014-11-10 1 views
1

인사말!멀티 스레딩 ArrayList 반복

Java (JavaFX8)에서 간단한 서버 모니터링 응용 프로그램을 작성했습니다. 현재 구현에서는 대상 머신을 하나씩 핑 (ping)하여 JavaFX LineChart에 그래프로 표시 할 수 있습니다. 각 기계는 ArrayList (Observable)에있는 "대상"객체입니다. 내 문제는 "하나씩"부분입니다. 대상을 ping하는 코드는 ping을 반환하는 Callable입니다. 필자는 어쨌든 한 번에 4 개 이상의 대상에 대해 ping을 수행 할 수 있도록 프로세스를 다중 스레드해야합니다. 과거의 시도로 인해 동일한 대상을 동시에 핑하는 4 개의 스레드와 같은 단점이 발생하여 매우 중요한 프로세서 중복이 발생했습니다. Heres는 내 전류 루프는 ...

public void beginPing() { 
    ExecutorService exec = Executors.newCachedThreadPool(); 

    Runnable r = new Runnable() { 
     @Override 
     public void run() { 
      while (true) { 
       for (Target t : targets) { 
        String ping = null; 
        if (t.flagsProperty().get().contains("A")) { 
         try { 
          Callable c = new Pinger(t); 
          ping = c.call().toString(); 
          switch (ping) { 
           case "TIME_OUT": 
            for (XYChart.Series s : lineChart.getData()) { 
             if (s.getName().equals(t.nameProperty().get())) { 
              addToChart(s, cycle, 00.00); 
             } 
            } 
            t.setStatus("TIME OUT"); 
            t.setLastrtt("TIME_OUT"); 
            t.setTimeouts(t.timeoutsProperty().get() + 1); 
            logUtil.log(LogUtil.INFO, t.nameProperty().get() + " - timed out!"); 
            break; 
           case "UNKNOWN_HOST": 
            t.setStatus("ERROR"); 
            t.setLastrtt("UNKNOWN HOST"); 
            logUtil.log(LogUtil.WARNING, t.nameProperty().get() + " - unknown host!"); 
            break; 
           case "UNREACHABLE": 
            t.setStatus("ERROR"); 
            t.setLastrtt("UNREACHABLE HOST"); 
            logUtil.log(LogUtil.WARNING, t.nameProperty().get() + " - is unreachable!"); 
            break; 
           default: 
            t.setLastrtt(ping); 
            t.setStatus("ACTIVE"); 
            for (XYChart.Series s : lineChart.getData()) { 
             if (s.getName().equals(t.nameProperty().get())) { 
              addToChart(s, cycle, Double.valueOf(ping)); 
             } 
            } 
            break; 
          } 
         } catch (Exception e) { 
          logUtil.log(LogUtil.CRITICAL, e.getMessage() + ", "+ e.getCause()); 
          e.printStackTrace(); 
         } 
        } 
       } 
       cycle++; 
       rangeChart(cycle); 
       updateInfo(); 
      } 
     } 
    }; 
    exec.execute(r); 
} 
+0

나는 당신이 그걸 위해 –

+1

에 대해 4 개의 개별 쓰레드를 만들어야한다고 생각한다.하지만 문제는 내가 그렇게해야한다는 것이다. 그래서 4 개의 개별 쓰레드는 같은 타겟 t에 대해 반복하지 않는다. 그렇지 않으면 동시에 4 개의 스레드가 동일한 작업을 수행하여 ConcurrentModificationExceptions 및 무의미한 중복성으로 이어질 수 있습니다. –

+0

JavaFX의 배열을 통해 멀티 스레딩 호출을위한 샘플 코드가 있습니다. [JavaFX2의 작업간에 진행률 표시기를 재설정하는 방법은?] (http://stackoverflow.com/questions/16368793/how -to-reset-progress-indicator-between-tasks-javafx2) – jewelsea

답변

1

내 느낌은 어떤 멀티 스레딩 서비스를 구현하지 않는 경우에만 인터페이스하지만 당신이, 일반 클래스처럼 호출 가능 클래스 Pinger의 오용이다. 이 같은 이상을 보여야하고 싶은 것은 :

//init 
Future<String> futures = new Future[targets.length]; 
String results = new String[targets.length]; 
ExecutorService service = Executors.newCachedThreadPool(); 

//start Threads 
for (int i = 0; i<targets.length; i++){  
    Pinger pinger= new Pinger(targets[i]); 
    future[i] = service.submit(pinger); 
} 

//wait for Threads to finish and get results 
for(int i = 0; i<futures.length; i++) 
    results[i] = futures[i].get() 

귀하의 Pinger의는 다음과 같아야합니다

public class Pinger implements Callable<String>{ 
    Pinger(Target target){ ... } 
    public String call(){ ... } 
} 

여기 당신이 완전히 구현 Example for Callables을 찾을 수 있습니다. 귀하의 코드에서 오직 하나의 Runnable을 ExecutorService에 제출하기 때문에 오직 두 개의 스레드 (Main과 Runnable) 만있을 것입니다. 당신은 결코 call() 메소드를 호출하지 않는다. 이것은 ExecutorService에 의해 수행된다. 이것을 Runnable Interface와 비교해 보면 Thread 호출 시작을 실행하거나 run()을 호출하는 대신 ExecutorService에 제출해야합니다. submit() 중에 반환되는 Future를 사용합니다. Callable의 개념을 이해하려고 시도하면 원하는 모든 것을 쓸 수 있습니다. ;-)

+0

나는 callable.call()을 호출하고, 즉시 .toString()을 호출한다. for 루프의 맨 위, 전환 직전. runnable은 JavaFX UI 스레드가 응답하지 않게합니다. Pinger는 이미 Callable을 구현합니다. –

+0

정확히이 문제가 발생했습니다. 메서드 호출()을 호출하면 다중 스레드가 완료되지 않고 순차적 인 동작 만 수행됩니다. 각 Callable을 ExecutorService에 제출해야합니다. – Zephro

+0

아마도 내가 명확히해야합니다. Callable Pinger를 대상 (Target)에서 동시에 호출해야한다는 것을 알고 있습니다. 문제는 필자가 핑 (ping)이 응답 (또는 타임 아웃)하자마자 Target 데이터를 업데이트해야한다는 것입니다. Futures와 예제를 사용하면 모든 응답을 기다린 다음 대상 변수를 모두 한 번에 업데이트해야합니다. 또한, 나는 어떻게 든 ExecutorService의 다른 스레드가 동일한 대상 (또는 한 스레드가 다른 스레드, 심지어 짝수)을 ping하지 않도록해야합니다. 본질적으로, 나는 무언가를 볼 수있는 사건의 흐름이 필요합니다 ... –

0

따라서, heres는 현재 작업 구현 ...

public void beginPing() { 
    safeTargets = new ArrayList<>(); //thread-safe collection 
    for (Target t : targets) { 
     safeTargets.add(t); 
    } 
    safeTargets = Collections.synchronizedList(targets); 

    exec = Executors.newCachedThreadPool(); 

    for (int i = 0; i < 4; i++) { //number of threads 
     exec.execute(new Runnable() { 
      @Override 
      public void run() { 
       while (true) { 
        for (Target t : safeTargets) { 
         String ping = null; 
         if (t.isActive() && !t.isIsBeingPinged()) { //checks if target is already being pinged by another thread and if it flagged as active and wishes to be pinged. 
          t.setIsBeingPinged(true); 
          t.setPinged(t.getPinged() + 1); //just to see how many times it has been pinged 
          t.setStatus("PINGING"); 
          try { 
           Callable c = new Pinger(t); 
           ping = c.call().toString(); 
           switch (ping) { 
            case "TIME_OUT": 
             t.setStatus("TIME OUT"); 
             t.setLastrtt("TIME_OUT"); 
             t.setTimeouts(t.timeoutsProperty().get() + 1); 
             logUtil.log(LogUtil.INFO, t.nameProperty().get() + " - timed out!"); 
             t.setIsBeingPinged(false); 
             break; 
            case "UNKNOWN_HOST": 
             t.setStatus("ERROR"); 
             t.setLastrtt("UNKNOWN HOST"); 
             logUtil.log(LogUtil.WARNING, t.nameProperty().get() + " - unknown host!"); 
             t.setIsBeingPinged(false); 
             break; 
            case "UNREACHABLE": 
             t.setStatus("ERROR"); 
             t.setLastrtt("UNREACHABLE HOST"); 
             logUtil.log(LogUtil.WARNING, t.nameProperty().get() + " - is unreachable!"); 
             t.setIsBeingPinged(false); 
             break; 
            default: 
             t.setLastrtt(ping); 
             t.setStatus("ACTIVE"); 
             t.setIsBeingPinged(false); 
             break; 
           } 
           System.out.println("C=" + t.getPinged() + " - " + t.nameProperty().get()); 
          } catch (Exception e) { 
           logUtil.log(LogUtil.CRITICAL, e.getMessage() + ", " + e.getCause()); 
           e.printStackTrace(); 
          } 
         } 
        } 
       } 
      } 
     }); 
    } 
} 

나는 결국 차트에 즉시 추가 제거했다.

  • 대상 목록 개체는 스레드 안전 동기화 목록 (kleopatra에서 제안한대로)에 추가됩니다.
  • 부울 변수가 대상 모델에 추가되어 현재 스레드 중 하나에 의해 핑되고 있는지 확인합니다. (t.isIsBeingPinged())
  • 동일한 풀에서 새로운 Runnable을 사용하여 데이터를 차트에 추가합니다.이 테이블은 낙하에서 더 높은 ping을 가진 대상을 피하기 위해 대상 목록을 반복하고 매 초마다 마지막 RTT를 차트에 추가합니다 뒤에 차트에.

매우 빠른 답변을 보내 주셔서 감사합니다.

+0

필요한 경우 참조 된 메소드/클래스를 게시합니다. –