2014-07-11 4 views
0

메소드가 N 번 호출 된 후에 만 ​​데이터를 트리거하는 데 어떤 데이터 구조를 사용하면 좋을까요? 클래스 내에서 카운터를 사용하는 것은 사소한 일이지만,이 작업을 수행하는 더 좋은 방법이 있는지 궁금합니다. 이것은 어떤 의미에서는 역방향 속도 제한 기와 같은 종류입니다.N 데이터를 호출 한 후에 만 ​​메소드를 트리거하는 Java 데이터 구조

for (int i = 0; i < 1000; ++i) { 
    call(); 
} 

void call() { 
    // trigger only once per 100 calls. 
    // e.g. static int i = 0; if (++i % 100) doSomething(); 
} 
+1

나는 thread-safe'private static '카운터가 괜찮다고 생각한다. –

+2

기본 카운터에 문제가 있습니까? – chrylis

+0

하찮은 사람은 완벽하게 받아 들일 수 있으며 일반적으로 바람직합니다. 왜 당신은 복잡성을 추가하고 싶습니까? "충분히 좋지 않습니다"이외에 해결하려는 문제가 있습니까? – Paul

답변

1

이 같은 정적 AtomicInteger을 사용할 수 있습니다 그리고

private static final AtomicInteger counter = new AtomicInteger(); 

당신의 call() 방법이 않습니다

if (counter.incrementAndGet() == N) { 
    do { 
     actualCall(); 
    } while (counter.addAndGet(-N) >= N); 
} 

actualCall() 것으로는 정확한 호출에서 호출 할 수 없습니다 숫자가 증가하여 N에 도달했습니다. 예를 들어 다른 스레드가 actualCall이 진행되는 동안 카운터를 2*N으로 가져 오는 경우 addAndGet(-N)N의 값을 반환하므로 루프가 계속 진행되고 actualCall이 다시 호출됩니다. 그러나 call()N 통화에 대해 actualCall 번의 전화가 있습니다.

0

아마도 상황과 의도를 자세히 설명해야합니다. 이것은 System.out.println으로 콘솔에 유출되는 일부 디버그 출력을 줄이기위한 것이므로 간단한 카운터가 문제가되지 않습니다.

그렇지 않으면 "침입성"과 "추상화"의 정도가 다른 여러 옵션이 있습니다.

첫 번째 질문은이 계산이 인스턴스를 기반으로해야하는지 또는 클래스 (정적)를 기반으로해야하는지 여부와 어쩌면 스레드 안전성 여부에 따라 달라집니다.

가장 간단한 경우, 질문에서 이미 제안한 내용과 dasblinkenlight에서 확인한 내용 (정적, 스레드 안전의 경우)을 사용할 수 있습니다.

class YourClass { 
    private CallPropagator c = new CountingCallPropagator(100); 

    void call() { 
     if (c.shouldPropagateCall()) { 
      // Really do it... 
     } 
    } 
} 

좋은 점은 당신이를 만들 수 있다는 것입니다 :

interface CallPropagator { 
    boolean shouldPropagateCall(); 
} 

class CountingCallPropagator implements CallPropagator { 
    private final int maxCount; 
    private int count = 0; 
    CountingCallPropagator(int maxCount) { 
     this.maxCount = maxCount; 
    } 
    @Override 
    public boolean shouldPropagateCall() { 
     count++; 
     if (count >= maxCount) { 
      count = 0; 
      return true; 
     } 
     return false; 
    } 
} 

한 후 다음 중 하나를 당신의 방법을 보호 : 추상화의

약간 높은 수준이 같은 인터페이스가 될 수 TimedCallPropagator과 같은 대체 구현은 카운트이라는 전화를 기반으로하지 않고 시간 만 기반으로 통화를 전달합니다 (예 : 단지 10 초 정도입니다. 다음 실제 작업 수행 구현 클래스의

하지만 여전히, 실제 작업을 수행 할 수 있는지 여부에 대한 결정은 오히려 명시 적이다, .

다음 추상화 수준은 호출 사이트에서 YourClass#call()의 사용을 완전히 제거하고 인터페이스로 완전히 대체하는 것입니다. 따라서 호출 대상에서 전화가 착신되었는지 여부를 결정 "숨기"할 것입니다. 은 호출 된 개체에서 원래 피 호출자를 작업 만 실행하는 것으로 "래핑"하는 옵션을 제공합니다 고정 된 간격으로.이다

는, 현재의 구조는 다음과 같습니다 주어진 :

class Caller { 
    void doCalls() { 
     for (int i = 0; i < 1000; ++i) { 
      call(); 
     } 
    } 
} 

당신은 Callee

class Caller { 

    private Callee callee = ...; 

    void doCalls() { 
     for (int i = 0; i < 1000; ++i) { 
      callee.call(); 
     } 
    } 
} 

같은 인터페이스를 소개하고이 인터페이스의 다양한 구현을 제공 할 수 있습니다. 예를 다시

class DirectCallee implements Callee { 
    @Override 
    public void call() { 
     // Do the actual work here 
    } 
} 


class IntervalCallee implements Callee { 

    private final Callee delegate; 
    private final int maxCount; 
    private int count = 0; 

    IntervalCallee(int maxCount, Callee delegate) { 
     this.delegate = delegate; 
     this.maxCount = maxCount; 
    } 

    @Override 
    public void call() { 
     count++; 
     if (count >= maxCount) { 
      count=0; 
      delegate.call(); 
     } 
    } 
} 

또는 시간 기반 전달을 수행 한 (그래서 또는 조합을 제공하고, 같은 "앞으로 모든 10 호, 마지막 3 호출 후 3 초 이내에 발생한 경우"또는 ...)

을 위해