System.currentTimeMillis () vs. nowa Date () vs. Calendar.getInstance (). GetTime ()

239

W Javie, jakie są implikacje wydajności i zasobów

System.currentTimeMillis() 

vs.

new Date() 

vs.

Calendar.getInstance().getTime()

Jak rozumiem, System.currentTimeMillis()jest najbardziej wydajny. Jednak w większości aplikacji ta długa wartość musiałaby zostać przekonwertowana na datę lub podobny obiekt, aby zrobić coś znaczącego dla ludzi.

Vihung
źródło

Odpowiedzi:

242

System.currentTimeMillis()jest oczywiście najbardziej wydajny, ponieważ nawet nie tworzy obiektu, ale new Date()tak naprawdę jest tylko cienkim opakowaniem o długim, więc nie jest daleko w tyle. Calendarz drugiej strony jest stosunkowo powolny i bardzo złożony, ponieważ musi poradzić sobie ze znacznie złożonością i wszystkimi osobliwościami związanymi z datami i godzinami (lata przestępne, czas letni, strefy czasowe itp.).

Zasadniczo dobrym pomysłem jest radzenie sobie tylko z długimi znacznikami czasu lub Dateobiektami w aplikacji i używanie ich tylko Calendarwtedy, gdy faktycznie trzeba wykonać obliczenia daty / godziny lub sformatować daty w celu wyświetlenia ich użytkownikowi. Jeśli musisz dużo tego zrobić, użycie Joda Time jest prawdopodobnie dobrym pomysłem, aby uzyskać czystszy interfejs i lepszą wydajność.

Michael Borgwardt
źródło
2
Jaka jest różnica między datownikiem a prądem Millis?
pinkpanther
1
@pinkpanther: „znacznik czasu” jest zwykle używany do opisania liczby całkowitej / długiej, która opisuje moment w czasie interpretowany jako sekundy lub milisekundy od „początku epoki”. Innymi słowy, currentTimeMillis () zwraca znacznik czasu.
Michael Borgwardt,
43

Patrząc na JDK, najbardziej wewnętrzny konstruktor Calendar.getInstance()ma to:

public GregorianCalendar(TimeZone zone, Locale aLocale) {
    super(zone, aLocale);
    gdate = (BaseCalendar.Date) gcal.newCalendarDate(zone);
    setTimeInMillis(System.currentTimeMillis());
}

więc już automatycznie robi to, co sugerujesz. Domyślny konstruktor daty zawiera to:

public Date() {
    this(System.currentTimeMillis());
}

Tak więc naprawdę nie trzeba specjalnie obliczać czasu systemowego, chyba że chcesz zrobić z nim matematykę przed utworzeniem za jej pomocą obiektu Kalendarz / Data. Muszę też zalecić użycie joda-time jako zamiennika własnych klas kalendarza / daty w Javie, jeśli twoim celem jest częsta praca z obliczeniami dat.

Esko
źródło
22

Jeśli korzystasz z randki, zdecydowanie zalecamy korzystanie z jodatime, http://joda-time.sourceforge.net/ . Używanie System.currentTimeMillis()pól, które datami, wydaje się bardzo złym pomysłem, ponieważ skończy się to niepotrzebnym kodem.

Zarówno data, jak i kalendarz są poważnie zepsute, a Kalendarz jest zdecydowanie najgorszym ze wszystkich.

Radzę, abyś używał go, System.currentTimeMillis()gdy faktycznie pracujesz z milisekundami, na przykład w ten sposób

 long start = System.currentTimeMillis();
    .... do something ...
 long elapsed = System.currentTimeMillis() -start;
krosenvold
źródło
28
Chciałem to skomentować, ponieważ twój przykład jest dokładnie jedną z rzeczy, których NIE powinieneś używać System.currentTimeMillis () do; nie jest to monotoniczne źródło zegara, więc nie można z nim wiarygodnie obliczyć upływającego czasu. Jeśli zegar systemowy zostanie zmieniony podczas wykonywania pomiaru czasu, otrzymasz dziwne (np. Negatywne) wyniki. Zamiast tego użyj System.nanoTime (), który jest monotoniczny, jeśli system bazowy obsługuje takie źródło zegara (patrz bugs.java.com/bugdatabase/view_bug.do?bug_id=6458294 )
rem
Strefa czasowa nie ma wpływu na system.currentTimeMillis. Zmiana czasu systemowego wpłynie na System.nanotime w taki sam sposób jak System.currentTimeMillis
Viktor
12

Wolę użyciu wartości zwracanych przez System.currentTimeMillis()wszelkiego rodzaju obliczeń i tylko użyć Calendarlub Datejeśli muszę naprawdę wyświetlić wartość, która jest odczytywana przez ludzi. Zapobiegnie to również 99% błędów związanych z czasem letnim. :)

Bombe
źródło
12

Na mojej maszynie próbowałem to sprawdzić. Mój wynik:

Calendar.getInstance (). GetTime () (* 1000000 razy) = 402ms
nowa data (). getTime (); (* 1000000 razy) = 18 ms
System.currentTimeMillis () (* 1000000 razy) = 16ms

Nie zapomnij o GC (jeśli używasz Calendar.getInstance()lub new Date())

Puzirki
źródło
1
Zastanawiam się, czy będzie jakaś różnica, jeśli wiele wątków
wywoła
7

W zależności od aplikacji możesz rozważyć użycie System.nanoTime()zamiast tego.

MykennaC
źródło
Dlaczego jego pytanie dotyczyło zasobów i wydajności, nanoTime () wykorzystuje więcej zasobów
WolfmanDragon,
Wspomniałem o tym, ponieważ jest to opcja, której nikt inny nie sugerował. Plakat nie określał platformy. Błąd SDN 6876279 sugeruje, że currentTimeMillis () i nanoTime () zajmują mniej więcej to samo w niektórych wersjach JDK. Plakat nie określił również ich potrzeb w zakresie dokładności, dla których oryginalna lista może być nieodpowiednia.
MykennaC
4
Jakkolwiek to może być późno, wszystkie przykłady w pytaniu mają absolutne pojęcie, która jest godzina, np. 1 348,770,313,071 milis od początku epoki Uniksa. Czas, który nanoTimepowraca, jest względny (zwykle do początku programu) i byłby nonsensem, gdybyś próbował zamienić go w datę.
Dunes
tak, ale można zapisać currentTimeilli i nano w jakimś statycznym kodzie podczas uruchamiania programu, a następnie użyć ich jako przesunięć, aby uzyskać dokładne nano z milli, używając podwójnego var = currentTimeStart - nanoTimeStart + nanoTimeNow
tgkprog
3

Próbowałem tego:

        long now = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            new Date().getTime();
        }
        long result = System.currentTimeMillis() - now;

        System.out.println("Date(): " + result);

        now = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            System.currentTimeMillis();
        }
        result = System.currentTimeMillis() - now;

        System.out.println("currentTimeMillis(): " + result);

I wynik był:

Data (): 199

currentTimeMillis (): 3

wiji
źródło
4
Jest to mikroprocesor i powinieneś być ostrożny, aby zaufać uzyskanym wynikom. Zajrzyj na stackoverflow.com/questions/504103/… .
Axel
1
Ten test porównawczy nie jest znaczący ani lepszy, pokazuje, że system operacyjny w Javie ma znaczenie. Przeprowadziłem ten sam test w pętli kilkanaście razy (przenoszenie inicjalizacji „teraz” i „wynik” poza pętlę) i miałem słodkie różnice przy każdym uruchomieniu: Date (): 322 do 330; currentTimeMillis (): 319 do 322. W niektórych innych uruchomieniach miałem Date (): 312 do 318; currentTimeMillis (): 324 do 335. Tak więc, IMHO są całkiem równoważne, w rzeczywistych przypadkach (również patrząc na źródło Date). JFYI, użyłem Java7 na Ubuntu.
Sampisa,
0

System.currentTimeMillis() jest oczywiście najszybszy, ponieważ jest to tylko jedno wywołanie metody i nie jest wymagane zbieranie śmieci.

Ramón
źródło
14
Twoja odpowiedź nie ma żadnej wartości, ponieważ jest tylko podzbiorem wcześniej zatwierdzonej odpowiedzi. Powinieneś starać się nie odpowiadać w ten sposób, zwłaszcza nie biorąc pod uwagę, że jest to bardzo stare pytanie z już istniejącą odpowiedzią jakościową.
Nicklas Gnejs Eriksson
1
Po drugie, śmieciarz nie jest wymagany w przypadku obiektów krótkoterminowych w przestrzeni Eden.
Niels Bech Nielsen