Seperti yang didokumentasikan dalam posting blog Waspadai System.nanoTime () di Jawa , pada sistem x86, Java's System.nanoTime () mengembalikan nilai waktu menggunakan CPU penghitung khusus . Sekarang pertimbangkan kasus berikut yang saya gunakan untuk mengukur waktu panggilan:
long time1= System.nanoTime();
foo();
long time2 = System.nanoTime();
long timeSpent = time2-time1;
Sekarang dalam sistem multi-core, bisa jadi setelah mengukur waktu1, utas dijadwalkan untuk prosesor yang berbeda yang penghitungnya lebih kecil dari pada CPU sebelumnya. Dengan demikian kita bisa mendapatkan nilai dalam time2 yang kurang dari time1. Dengan demikian kita akan mendapatkan nilai negatif dalam timeSpent.
Mempertimbangkan kasus ini, bukankah itu System.nanotime cukup berguna untuk saat ini?
Saya tahu bahwa mengubah waktu sistem tidak mempengaruhi nanotime. Itu bukan masalah yang saya jelaskan di atas. Masalahnya adalah bahwa setiap CPU akan menyimpan penghitung yang berbeda sejak dihidupkan. Penghitung ini bisa lebih rendah pada CPU kedua dibandingkan dengan CPU pertama. Karena utas dapat dijadwalkan oleh OS ke CPU kedua setelah mendapatkan waktu1, nilai timeSpent mungkin salah dan bahkan negatif.
Jawaban:
Jawaban ini ditulis pada tahun 2011 dari sudut pandang apa yang sebenarnya dilakukan oleh Sun JDK pada sistem operasi saat itu. Itu sudah lama sekali! jawaban leventov menawarkan perspektif yang lebih mutakhir.
Posting itu salah, dan
nanoTime
aman. Ada komentar pada posting yang menghubungkan ke posting blog oleh David Holmes , seorang pria realtime dan concurrency di Sun. Ia mengatakan:Jadi, pada Windows, ini merupakan masalah hingga WinXP SP2, tetapi tidak sekarang.
Saya tidak dapat menemukan bagian II (atau lebih) yang berbicara tentang platform lain, tetapi artikel itu tidak menyertakan komentar bahwa Linux telah mengalami dan memecahkan masalah yang sama dengan cara yang sama, dengan tautan ke FAQ untuk clock_gettime (CLOCK_REALTIME) , yang mengatakan:
Jadi, jika tautan Holmes dapat dibaca sebagai menyiratkan
nanoTime
panggilan ituclock_gettime(CLOCK_REALTIME)
, maka itu aman pada kernel 2.6.18 pada x86, dan selalu pada PowerPC (karena IBM dan Motorola, tidak seperti Intel, benar-benar tahu cara mendesain mikroprosesor).Sayangnya, tidak disebutkan SPARC atau Solaris. Dan tentu saja, kami tidak tahu apa yang IBM JVM lakukan. Tapi Sun JVM di Windows dan Linux modern bisa melakukannya dengan benar.
EDIT: Jawaban ini didasarkan pada sumber yang dikutipnya. Tetapi saya masih khawatir bahwa itu mungkin benar-benar salah. Beberapa informasi terbaru akan sangat berharga. Saya baru saja menemukan tautan ke artikel empat tahun yang lebih baru tentang jam Linux yang dapat bermanfaat.
sumber
void foo() { Thread.sleep(40); }
saya mendapat waktu negatif (-380 ms!) MenggunakanAthlon 64 X2 4200+
prosesor tunggalSaya melakukan sedikit pencarian dan menemukan bahwa jika seseorang menjadi jagoan maka ya itu mungkin dianggap tidak berguna ... dalam situasi tertentu ... itu tergantung pada seberapa sensitif waktu kebutuhan Anda ...
Lihatlah kutipan ini dari situs Java Sun:
Java juga memiliki peringatan untuk metode nanoTime () :
Tampaknya satu-satunya kesimpulan yang dapat ditarik adalah bahwa nanoTime () tidak dapat diandalkan sebagai nilai yang akurat. Dengan demikian, jika Anda tidak perlu mengukur waktu yang hanya berjarak nano detik, maka metode ini cukup baik bahkan jika nilai yang dihasilkan negatif. Namun, jika Anda membutuhkan ketelitian yang lebih tinggi, mereka tampaknya menyarankan agar Anda menggunakan JAVA RTS.
Jadi untuk menjawab pertanyaan Anda ... no nanoTime () tidak berguna .... itu bukan metode yang paling bijaksana untuk digunakan dalam setiap situasi.
sumber
-100
,-99
,-98
(Nilai jelas jauh lebih besar dalam praktek). Mereka pergi ke arah yang benar (meningkat), jadi tidak ada masalah di sini.Tidak perlu diperdebatkan, cukup gunakan sumbernya. Di sini, SE 6 untuk Linux, buat kesimpulan sendiri:
sumber
Sejak Java 7,
System.nanoTime()
dijamin aman dengan spesifikasi JDK.System.nanoTime()
Javadoc memperjelas bahwa semua doa yang teramati dalam JVM (yaitu, di semua utas) adalah monoton:Implementasi JVM / JDK bertanggung jawab untuk meniadakan ketidakkonsistenan yang dapat diamati ketika utilitas OS yang mendasarinya dipanggil (misalnya yang disebutkan dalam jawaban Tom Anderson ).
Mayoritas jawaban lama lainnya untuk pertanyaan ini (ditulis pada 2009-2012) menyatakan FUD yang mungkin relevan untuk Java 5 atau Java 6 tetapi tidak lagi relevan untuk versi Jawa modern.
Perlu disebutkan, meskipun JDK menjamin
nanoTime()
keamanan, ada beberapa bug di OpenJDK yang membuatnya tidak menjunjung tinggi jaminan ini pada platform tertentu atau dalam keadaan tertentu (misalnya JDK-8040140 , JDK-8184271 ). Tidak ada bug terbuka (dikenal) di OpenJDK wrtnanoTime()
saat ini, tetapi penemuan bug baru atau regresi dalam rilis OpenJDK yang lebih baru seharusnya tidak mengejutkan siapa pun.Dengan mengingat hal itu, kode yang digunakan
nanoTime()
untuk pemblokiran waktunya, tunggu interval, batas waktu, dll. Sebaiknya memperlakukan perbedaan waktu negatif (batas waktu) sebagai nol daripada membuang pengecualian. Praktek ini juga disukai karena konsisten dengan perilaku semua metode menunggu waktunya di semua kelas dijava.util.concurrent.*
, misalnyaSemaphore.tryAcquire()
,Lock.tryLock()
,BlockingQueue.poll()
, dllMeskipun demikian,
nanoTime()
harus tetap lebih disukai untuk menerapkan pemblokiran waktunya, tunggu interval, batas waktu, dll.currentTimeMillis()
Karena yang terakhir adalah subjek dari fenomena "waktu mundur" (misalnya karena koreksi waktu server), yaitucurrentTimeMillis()
tidak cocok untuk mengukur interval waktu sama sekali. Lihat jawaban ini untuk informasi lebih lanjut.Alih-alih menggunakan
nanoTime()
untuk pengukuran waktu eksekusi kode secara langsung, kerangka kerja benchmarking khusus dan profiler sebaiknya digunakan, misalnya JMH dan async-profiler dalam mode profil jam dinding .sumber
Penafian: Saya adalah pengembang perpustakaan ini
Anda mungkin lebih suka ini:
http://juliusdavies.ca/nanotime/
Tapi itu menyalin file DLL atau Unix .so (objek bersama) ke direktori home pengguna saat ini sehingga dapat memanggil JNI.
Beberapa informasi latar belakang ada di situs saya di:
http://juliusdavies.ca/posix_clocks/clock_realtime_linux_faq.html
sumber
Linux mengoreksi perbedaan antara CPU, tetapi Windows tidak. Saya sarankan Anda menganggap System.nanoTime () hanya akurat sekitar 1 mikro-detik. Cara sederhana untuk mendapatkan penghitungan waktu yang lebih lama adalah dengan menelepon foo () 1000 atau lebih dan membagi waktu dengan 1000.
sumber
Sama sekali tidak berguna. Penggemar waktu yang tepat menunjukkan masalah multi-core, tetapi dalam aplikasi kata-kata sebenarnya seringkali secara radikal lebih baik daripada currentTimeMillis ().
Ketika menghitung posisi grafik dalam bingkai menyegarkan nanoTime () mengarah ke gerakan JAUH lebih halus dalam program saya.
Dan saya hanya menguji pada mesin multi-core.
sumber
Saya telah melihat waktu berlalu negatif yang dilaporkan dari menggunakan System.nanoTime (). Agar jelas, kode yang dimaksud adalah:
dan variabel 'elapsedNanos' memiliki nilai negatif. (Saya yakin bahwa panggilan perantara juga membutuhkan waktu kurang dari 293 tahun, yang merupakan titik meluap untuk nanos yang disimpan dalam waktu lama :)
Ini terjadi menggunakan IBM v1.5 JRE 64bit pada perangkat keras IBM P690 (multi-core) yang menjalankan AIX. Saya hanya melihat kesalahan ini terjadi sekali, jadi sepertinya sangat jarang. Saya tidak tahu penyebabnya - apakah ini masalah khusus perangkat keras, cacat JVM - Saya tidak tahu. Saya juga tidak tahu implikasi untuk akurasi nanoTime () secara umum.
Untuk menjawab pertanyaan awal, saya tidak berpikir nanoTime tidak berguna - ini menyediakan waktu sub-milidetik, tetapi ada risiko aktual (bukan hanya teoritis) karena tidak akurat yang perlu Anda perhitungkan.
sumber
Ini sepertinya tidak menjadi masalah pada Core 2 Duo yang menjalankan Windows XP dan JRE 1.5.0_06.
Dalam tes dengan tiga utas saya tidak melihat System.nanoTime () mundur. Prosesor sama-sama sibuk, dan utas pergi tidur sesekali untuk memancing ulir bergerak.
[EDIT] Saya kira itu hanya terjadi pada prosesor yang terpisah secara fisik, yaitu penghitung disinkronkan untuk beberapa core pada die yang sama.
sumber
Tidak, ini bukan ... Itu hanya tergantung pada CPU Anda, periksa Pengatur Waktu Presisi Tinggi untuk bagaimana / mengapa semuanya diperlakukan berbeda sesuai dengan CPU.
Pada dasarnya, baca sumber Java Anda dan periksa apa versi Anda dengan fungsi tersebut, dan jika berfungsi melawan CPU Anda akan menjalankannya.
IBM bahkan menyarankan Anda menggunakannya untuk tolok ukur kinerja (pos tahun 2008, tetapi diperbarui).
sumber
Saya menghubungkan ke apa yang pada dasarnya adalah diskusi yang sama di mana Peter Lawrey memberikan jawaban yang baik. Mengapa saya mendapatkan waktu berlalu negatif menggunakan System.nanoTime ()?
Banyak orang menyebutkan bahwa di Java System.nanoTime () dapat mengembalikan waktu negatif. Saya minta maaf karena mengulangi apa yang sudah dikatakan orang lain.
Akan keren jika System.nanoTime () mengembalikan coreID di mana ia dieksekusi.
sumber
Java adalah lintas platform, dan nanoTime tergantung pada platform. Jika Anda menggunakan Java - saat tidak menggunakan nanoTime. Saya menemukan bug nyata di implementasi jvm yang berbeda dengan fungsi ini.
sumber
Dokumentasi Java 5 juga merekomendasikan penggunaan metode ini untuk tujuan yang sama.
Java 5 API Doc
sumber
Juga,
System.currentTimeMillies()
berubah ketika Anda mengubah jam sistem Anda, sementaraSystem.nanoTime()
tidak, sehingga yang terakhir lebih aman untuk mengukur durasi.sumber
nanoTime
sangat tidak aman untuk menentukan waktu. Saya mencobanya pada algoritma pengujian primality dasar saya dan memberikan jawaban yang secara harfiah terpisah satu sama lain untuk input yang sama. Jangan gunakan metode konyol itu. Saya membutuhkan sesuatu yang lebih akurat dan tepat daripada mendapatkan waktu milis, tetapi tidak seburuk itunanoTime
.sumber