Dalam program bersamaan, pemrogram akan memberikan perhatian khusus pada sinkronisasi data antara proses atau thread yang berbeda, terutama ketika beberapa thread memodifikasi variabel yang sama pada saat yang sama, sinkronisasi yang andal atau tindakan lain harus diambil untuk memastikan bahwa data diubah dengan benar Intinya di sini Prinsipnya adalah: jangan berasumsi urutan eksekusi instruksi. Anda tidak dapat memprediksi urutan eksekusi instruksi di antara thread yang berbeda.
Namun dalam program single-thread, biasanya mudah bagi kita untuk berasumsi bahwa instruksi dijalankan secara berurutan, jika tidak, kita dapat membayangkan perubahan buruk apa yang akan terjadi pada program tersebut. Model yang ideal adalah: urutan eksekusi berbagai instruksi adalah unik dan berurutan. Urutan ini adalah urutan penulisannya dalam kode, terlepas dari prosesor atau faktor lainnya itu adalah Model berdasarkan sistem von Neumann. Tentu saja, asumsi ini masuk akal dan jarang terjadi secara tidak normal dalam praktiknya, namun kenyataannya, tidak ada arsitektur multiprosesor modern yang mengadopsi model ini karena terlalu tidak efisien. Dalam optimasi kompilasi dan pipeline CPU, hampir semuanya melibatkan penyusunan ulang instruksi.
penyusunan ulang waktu kompilasi
Penataan ulang waktu kompilasi yang khas adalah menyesuaikan urutan instruksi untuk mengurangi jumlah pembacaan dan penyimpanan register sebanyak mungkin tanpa mengubah semantik program, dan untuk sepenuhnya menggunakan kembali nilai register yang disimpan.
Misalkan instruksi pertama menghitung suatu nilai dan menugaskannya ke variabel A dan menyimpannya dalam register. Instruksi kedua tidak ada hubungannya dengan A tetapi perlu menempati sebuah register (dengan asumsi instruksi tersebut akan menempati register di mana A berada). instruksi menggunakan nilai A dan Tidak ada hubungannya dengan instruksi kedua. Kemudian jika menurut model konsistensi sekuensial, A dimasukkan ke dalam register setelah instruksi pertama dijalankan, A tidak ada lagi ketika instruksi kedua dijalankan, dan A dibaca lagi ke dalam register ketika instruksi ketiga dijalankan, dan selama proses ini, nilai A tidak berubah. Biasanya compiler akan menukar posisi instruksi kedua dan ketiga, sehingga A ada di register di akhir instruksi pertama, dan kemudian nilai A dapat dibaca langsung dari register, sehingga mengurangi overhead pembacaan berulang.
Pentingnya penataan ulang saluran pipa
Hampir semua CPU modern menggunakan mekanisme pipeline untuk mempercepat pemrosesan instruksi. Secara umum, sebuah instruksi memerlukan beberapa siklus jam CPU untuk diproses, dan melalui eksekusi paralel dari pipeline, beberapa instruksi dapat dieksekusi dalam siklus jam yang sama metodenya dinyatakan secara sederhana. Bagi saja instruksinya menjadi beberapa bagian Siklus eksekusi, seperti pembacaan, pengalamatan, penguraian, eksekusi, dan langkah-langkah lainnya, diproses dalam komponen yang berbeda. Pada saat yang sama, di unit eksekusi UE, unit fungsional dibagi menjadi beberapa komponen, seperti komponen penjumlahan, komponen perkalian , dan memuat komponen, elemen penyimpanan, dll., selanjutnya dapat mewujudkan eksekusi paralel dari perhitungan yang berbeda.
Arsitektur pipeline menentukan bahwa instruksi harus dijalankan secara paralel, bukan seperti yang dipertimbangkan dalam model sekuensial. Penataan ulang kondusif untuk memanfaatkan pipa sepenuhnya, sehingga mencapai efek superskalar.
Pastikan ketertiban
Meskipun instruksi belum tentu dieksekusi sesuai urutan penulisannya, tidak ada keraguan bahwa dalam lingkungan single-thread, efek akhir dari eksekusi instruksi harus konsisten dengan efeknya dalam eksekusi berurutan, jika tidak, optimalisasi ini akan kehilangan signifikansinya.
Biasanya, prinsip-prinsip di atas akan dipenuhi baik pemesanan ulang instruksi dilakukan pada waktu kompilasi atau waktu proses.
Menyusun ulang dalam model penyimpanan Java
Dalam Java Memory Model (JMM), penataan ulang merupakan bagian yang sangat penting, terutama dalam pemrograman konkuren. JMM memastikan semantik eksekusi berurutan melalui aturan terjadi-sebelum. Jika Anda ingin thread yang melakukan operasi B mengamati hasil thread yang melakukan operasi A, maka A dan B harus memenuhi prinsip terjadi-sebelum operasi pada mereka. Penyortiran untuk meningkatkan kinerja program.
Kata kunci volatil dapat memastikan visibilitas variabel, karena operasi pada volatil semuanya ada di Memori Utama, dan Memori Utama digunakan bersama oleh semua thread. Harga di sini adalah kinerja dikorbankan, dan register atau Cache tidak dapat digunakan karena keduanya bukan Global , visibilitas tidak dapat dijamin dan pembacaan kotor dapat terjadi.
Fungsi lain dari volatil adalah untuk mencegah penyusunan ulang secara lokal. Instruksi pengoperasian pada variabel volatil tidak akan disusun ulang, karena jika disusun ulang, masalah visibilitas dapat terjadi.
Dalam hal memastikan visibilitas, kunci (termasuk kunci eksplisit, kunci objek) dan pembacaan dan penulisan variabel atom dapat memastikan visibilitas variabel. Namun, metode implementasinya sedikit berbeda. Misalnya, kunci sinkronisasi memastikan bahwa data dibaca ulang dari memori untuk menyegarkan cache ketika kunci dilepaskan, data ditulis kembali ke memori untuk memastikan bahwa datanya terlihat, sedangkan variabel volatil hanya membaca dan menulis memori.