2014-09-23 4 views
1

을 계속대기가 시작 JAVA 응용 프로그램을 계속 내가 작성한 클래스를 응용 프로그램

클래스 코드는 아래에 제시된, 내가 궁금한 점은 바로 이것이 올바른 방법인가? 그것은 우아한 솔루션처럼 보이지 않습니다. 이렇게 실행을 차단하고 인스턴스를 반복해서 가져 오는 것입니다.

public class Synchronizer{ 
    private static Calendar c; 

    public static void timeInSync(){ 
     do{ 
      c = Calendar.getInstance(); 
     } 
     while(c.get(Calendar.SECOND) % 5 != 0); 
    } 
} 

Synchronizer.timeInSync()가 다른 클래스의 생성자에서 호출하고 해당 클래스의 인스턴스는 main 메소드의 시작 부분에 생성됩니다. 그런 다음 응용 프로그램은 매 5 초마다 호출되는 TimerTask로 영원히 실행됩니다.

시간을 동기화하는 더 깨끗한 해결책이 있습니까?

업데이트 :

나는 명확하게 명시되지 않았다고 생각하지만 내가 여기 찾고 있어요 것은 바쁜 대기를하지 않고 시스템 시간과 동기하는 것입니다.

그래서 내가 @ChrisK에서 알 수 있듯이

12:19:00 
12:19:05 
12:19:10 
... 
+0

System.currentTimeMillis에 익숙합니까? –

+0

그 대신에 [Timer] (http://docs.oracle.com/javase/7/docs/api/java/util/Timer.html)를 사용할 수도 있습니다. – Compass

+0

더 명확한 질문을 위해 질문을 업데이트했지만 Durandal의 해답은 나에게 매우 만족 스럽습니다. – ickarsim

답변

2

는 (때로는 폴링로 함), 및 에너지 사용의 측면에서 또한 예 자사의 프로세서 사용 측면에서 비효율적이고.코드는 OS가 허용 할 때마다 실행되며 다른 작업을 위해 CPU를 사용하지 못하도록하거나 다른 작업이없는 경우 CPU가 낮잠을자는 것을 막아 에너지 낭비 (CPU 가열, 배터리 방전 ...).

당신이해야 할 일은 당신이 무언가를하고 싶을 때까지 스레드를 잠자기 상태로 두는 것입니다. 이렇게하면 CPU가 다른 작업을 수행하거나 절전 모드로 전환됩니다.

다음을 수행하는 java.lang.Thread에 대한 방법이 있습니다. Thread.sleep(long milliseconds) (추가 nanos 매개 변수를 사용하는 사촌도 있지만 VM에서 무시할 수 있으며 그 종류의 정밀도는 거의 필요하지 않습니다.).

우선 일을해야 할 때 을 먼저 결정하십시오. 그럼 그때까지 자. 순진 구현은 그렇게 볼 수 있었다 :

public static void waitUntil(long timestamp) { 
    long millis = timestamp - System.currentTimeMillis(); 
    // return immediately if time is already in the past 
    if (millis <= 0) 
     return; 
    try { 
     Thread.sleep(millis); 
    } catch (InterruptedException e) { 
     throw new RuntimeException(e.getMessage(), e); 
    } 
} 

너무 엄격한 요구 사항이없는 정확하게 시간을 명중에, 당신이 지정된 시간 (몇 십 MS 합리적으로 가까운 반환을 기대할 수 있으면이 잘 작동 멀리 아마) 시간이 너무 멀지 않은 미래 (몇 초 가기). 그러나 은 운영체제가 실제로 바쁠 때 가끔 나중에 반환 할 가능성이 높은 경우가 종종있는을 보장하지 않습니다.

약간 더 정확한 방법은 reuired 수면 시간을 결정하는 것입니다, 수면 시간 동안 다시 필요한 수면, 수면 다시 필요한 수면 시간은 매우 작은 될 때까지 등 시간과를 평가 한 후 나머지 몇 밀리 초 대기.

그러나 System.currentTimeMillis()는 실제 시간 해상도를 보장하지 않습니다. 밀리 초마다 한 번씩 바뀔 수 있지만, 10ms마다 10 번씩 변경 될 수도 있습니다 (플랫폼에 따라 다름). System.nanoTime()도 동일합니다.

멀티 태스킹 환경 (요즘 거의 모든 곳)의 고급 프로그래밍 언어에서는 정확한 시점을 기다리는 것이 불가능합니다. 엄격한 요구 사항이있는 경우 특정 시간에 인터럽트을 작성하고 인터럽트에서 이벤트를 처리하도록 운영 체제 세부 사항을 설정해야합니다 (즉, 어셈블러 또는 인터럽트 핸들러의 경우 C를 의미). 대부분의 일반 응용 프로그램에서는이 기능이 필요하지 않지만 게임/응용 프로그램에서는 일반적으로 몇 ms +/-가 중요하지 않습니다.

+0

정확히 내가 무엇을 찾고 있었는지 고맙습니다. – ickarsim

1

를 얻을 수 있어야합니다, 당신은 단지 System.currentTimeMillis()에 직접 호출하여 단순화 할 수 있습니다. 예를 들어

: 시간의 표현이 밀리 초에 있기 때문에 당신이 5000 비교 값을 변경해야

long time = 0; 
    do 
    { 
     time = System.currentTimeMillis(); 

    } while (time % 5000 != 0); 

참고. 또한

, 루핑 호출이 프로세서의 가용성과 이것 저것에 의존하기 때문에, 직접이 같은 어떤 비교를하고 가능한 함정이있다, 그래서 반환 이와 같은 구현 한 통화를 할 수있는 가능성이 있습니다 :

`1411482384999` 

다음 조건이 하드웨어 가용성 덕분에 생략 된 것을 의미 루프 반환

`1411482385001` 

에서 다음 호출.

당신이 스케줄러에 내장 된 사용하려면

, 나는 당신이 사용해야 여기 java: run a function after a specific number of seconds

0

비슷한 질문에 대한 답변을보고 제안

System.nanoTime() 

대신

System.currentTimeMillis() 

때문에 시스템 시간 대신 측정 된 경과 시간을 반환하므로 nanoTime은 시스템 시간 변경의 영향을받지 않습니다. 지금 대기 바쁜 라고 한 어떤

public class Synchronizer 
{ 
    public static void timeInSync() 
    { 
     long lastNanoTime = System.nanoTime(); 
     long nowTime = System.nanoTime(); 
     while(nowTime/1000000 - lastNanoTime /1000000 < 5000) 
     { 
      nowTime = System.nanoTime(); 
     }  
    } 
} 
0

첫 번째 요점은 절전 대기를 절대로 사용해서는 안된다는 것입니다. 자바에서는 Object.wait(timeout) 또는 Thread.sleep(timeout)을 사용하여 대기 중을 방지 할 수 있습니다. 나중에 모니터 잠금을 잃을 필요가 없으므로 나중에 더 적합합니다.

다음으로 두 가지 방법을 사용하여 시간 조건이 충족 될 때까지 대기 할 수 있습니다. 전체 대기 시간을 미리 계산하거나 루프에서 작은 시간 간격을 기다리면서 조건을 점검 할 수 있습니다.

내가 여기에 두 가지 접근법을 설명합니다 :

 private static long nextWakeTime(long time) { 
      if (time/1000 % 5 == 0) { // current time is multiple of five seconds 
       return time; 
      } 
      return (time/1000/5 + 1) * 5000; 
     } 


     private static void waitUsingCalculatedTime() { 
      long currentTime = System.currentTimeMillis(); 
      long wakeTime = nextWakeTime(currentTime); 

      while (currentTime < wakeTime) { 
       try { 
        System.out.printf("Current time: %d%n", currentTime); 
        System.out.printf("Wake time: %d%n", wakeTime); 
        System.out.printf("Waiting: %d ms%n", wakeTime - currentTime); 
        Thread.sleep(wakeTime - currentTime); 
       } catch (InterruptedException e) { 
        // ignore 
       } 
       currentTime = System.currentTimeMillis(); 
      } 
     } 

     private static void waitUsingSmallTime() { 
      while (System.currentTimeMillis()/1000 % 5 != 0) { 
       try { 
        System.out.printf("Current time: %d%n", System.currentTimeMillis()); 
        Thread.sleep(100); 
       } catch (InterruptedException e) { 
        // ignore 
       } 
      } 
     } 

당신이 볼 수 있듯이, 미리 계산 된 시간을 기다리고 더 복잡하지만 일반적인 경우에이에서 수행되기 때문에 그것은 (더 정확하고 더 효율적입니다 단일 반복). 작은 시간 간격 동안 반복적으로 대기하는 것은 더 간단하지만 덜 효율적이고 정확합니다 (정밀도는 선택한 시간 간격의 크기에 따라 다릅니다).

또한 내가 시간 조건이 만족 될 경우 계산 방법 참고 : 초를 계산하고 다섯의 여러 경우에만 다음 검사 할 필요가 첫 번째 단계에서

(time/1000 % 5 == 0) 

. 다른 대답에서 제안 된대로 time % 5000 == 0으로 확인하는 것은 잘못되었습니다. 이는 매 5 초마다 1 밀리 초 동안 만 적용됩니다.