Mengapa Sinkronisasi Thread
Karena ketika kami memiliki beberapa utas untuk mengakses variabel atau objek pada saat yang sama, jika ada operasi baca dan tulis di utas ini, itu akan menyebabkan kebingungan pada nilai variabel atau status objek, yang menghasilkan pengecualian program. Misalnya, jika rekening bank dioperasikan oleh dua utas secara bersamaan, satu menarik 100 yuan dan yang lainnya menghemat 100 yuan. Dengan asumsi bahwa akun awalnya memiliki 0 yuan, apa yang akan terjadi jika utas penarikan dan utas penghematan terjadi pada saat yang sama? Jika penarikan uang tidak berhasil, saldo akun adalah 100. Jika penarikan uang berhasil, saldo akun adalah 0. Jadi yang mana? Sulit menjelaskan dengan jelas. Oleh karena itu, sinkronisasi multi-threaded adalah untuk menyelesaikan masalah ini.
1. Kode saat tidak sinkron
Bank.java ThreadTest;/** * @Author WW * */Bank Public Class {private int count = 0; // Saldo Akun // uang public void addMoney (int money) {coun t += money; out .println (System.currentTimeMillis ()+"Simpan:"+uang); ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::; "BUKUP:+Uang); (String args []) {final Bank Bank = new b ank (); thread tad = thread baru (runnable baru () { @ override public void run () {// TODO METODE AUTO-ENTECEERATED Stub while (true) { {Thread.sleep (1000); /n ");}}}); thread tsub = utas baru (runnable baru () {@Override public void run () {// TODO Metode yang dihasilkan otomatis Stub while (true) {Bank.submoney (100); Bank .lookmoney (); });
Kode ini sangat sederhana, saya tidak akan menjelaskannya. Saya mencegat beberapa dari mereka, apakah itu sangat berantakan, dan saya tidak bisa memahami tulisannya.
Saldo Saldo Saldo yang Tidak Cukup: 0
Saldo Saldo Saldo yang Tidak Cukup: 100
1441790503354 Setoran: 100
Saldo Akun: 100
1441790504354 Setoran: 100
Saldo Akun: 100
1441790504354 Take Out: 100
Saldo Akun: 100
1441790505355 Setoran: 100
Saldo Akun: 100
1441790505355 Take Out: 100
Saldo Akun: 100
2. Gunakan kode sinkron
(1) Metode sinkronisasi:
Ada metode untuk memodifikasi kata kunci yang disinkronkan. Karena setiap objek di Java memiliki kunci bawaan, saat memodifikasi metode dengan kata kunci ini, kunci bawaan melindungi seluruh metode. Sebelum memanggil metode ini, Anda perlu mendapatkan kunci bawaan, jika tidak, ia akan berada dalam keadaan pemblokiran.
Bank.java yang dimodifikasi
Mari kita lihat hasil berjalan:
Saldo Saldo Saldo yang Tidak Cukup: 0
Saldo Saldo Saldo yang Tidak Cukup: 0
1441790837380Saved: 100
Saldo Akun: 100
1441790838380 Take Out: 100
Saldo Akun: 0
1441790838380Saved: 100
Saldo Akun: 100
1441790839381 Dihapus: 100
Saldo Akun: 0
Saya merasa itu mengerti secara instan.
Catatan: Kata kunci yang disinkronkan juga dapat memodifikasi metode statis.
(2) menyinkronisasi blok kode
Artinya, ada blok pernyataan yang dimodifikasi oleh kata kunci yang disinkronkan. Blok pernyataan yang dimodifikasi oleh kata kunci ini akan ditambahkan secara otomatis dengan kunci bawaan untuk mencapai sinkronisasi
Bank.java Code adalah sebagai berikut:
Paket ThreadTest;/** * @Author WW * */Bank Public Class {private int count = 0; // Saldo Akun // Deposit Uang Public Void AddMoney (Int Money) {Sinkronisasi (ini) {Count += Money; System.out.println (System.CurrentTimeMillis ()+"Simpan:"+Uang); .println (Saldo Tidak Cukup "); {System.out.println ("Saldo Akun:"+Count);
Hasil operasi adalah sebagai berikut:
Saldo Saldo Saldo yang Tidak Cukup: 0
1441791806699Saved: 100
Saldo Akun: 100
1441791806700 Take Out: 100
Saldo Akun: 0
1441791807699Saved: 100
Saldo Akun: 100
Efeknya mirip dengan metode ini.
Catatan: Sinkronisasi adalah operasi tinggi-overhead, sehingga konten yang disinkronkan harus diminimalkan. Biasanya tidak perlu menyinkronkan seluruh metode, cukup gunakan blok kode yang disinkronkan untuk menyinkronkan kode kunci.
(3) Gunakan variabel domain khusus (volatil) untuk mencapai sinkronisasi utas
Kata kunci A.Volatile menyediakan mekanisme bebas kunci untuk mengakses variabel domain
b. Menggunakan volatile untuk memodifikasi domain setara dengan memberi tahu mesin virtual bahwa domain dapat diperbarui oleh utas lain.
c. Oleh karena itu, setiap kali Anda menggunakan bidang ini, Anda perlu menghitung ulang, alih -alih menggunakan nilai dalam register
D.Volatile tidak menyediakan operasi atom apa pun, juga tidak dapat digunakan untuk memodifikasi variabel jenis akhir
Bank.java Code adalah sebagai berikut:
Paket ThreadTest;/ ** * @Author WW * */ Bank Public Class {Private Volatile Int Count = 0; // Saldo Akun // Hemat Uang Kerja Publik AddMoney (Int Money) {Count += Money; (System.currentTimeMillis () + "Simpan:" + uang); ;} Count -= Money; " + hitung);}}
Bagaimana efek operasinya?
Saldo Saldo Saldo yang Tidak Cukup: 0
Saldo Saldo Saldo yang Tidak Cukup: 100
1441792010959Saved: 100
Saldo Akun: 100
1441792011960 Take Out: 100
Saldo Akun: 0
1441792011961Saved: 100
Saldo Akun: 100
Apakah karena saya tidak bisa memahaminya lagi dan berantakan lagi? Mengapa ini? Itu karena volatil tidak dapat menjamin operasi atom, sehingga volatile tidak dapat menggantikan disinkronkan. Selain itu, volatile akan mengatur kompiler untuk mengoptimalkan kode, jadi jika Anda dapat menggunakannya, itu tidak akan berlaku. Prinsipnya adalah bahwa setiap kali utas ingin mengakses variabel yang dimodifikasi dengan volatile, dibaca dari memori, bukan dalam cache, sehingga nilai variabel yang diakses oleh masing -masing utas adalah sama. Ini memastikan sinkronisasi.
(4) Gunakan kunci masuk kembali untuk mencapai sinkronisasi utas
Paket Java.util.concurrent baru telah ditambahkan ke Javase5.0 untuk mendukung sinkronisasi. Kelas Reentrantlock adalah kunci reentrant, saling eksklusif yang mengimplementasikan antarmuka kunci.
Metode umum kelas Reenreantlock adalah:
Reentrantlock (): Buat instance reentrantlock
lock (): dapatkan kunci
Buka Kunci (): Catatan Reentrantlock: Reentrantlock () juga memiliki konstruktor yang dapat membuat kunci yang adil, tetapi tidak disarankan untuk menggunakannya karena dapat sangat mengurangi efisiensi berjalan program.
Kode bank.java dimodifikasi sebagai berikut:
Paket Threadtest; //Anda perlu mendeklarasikan kunci kunci pribadi ini = reentrantlock baru (); tln (System .currentTimeMillis () + "Simpan:" + uang);} Akhirnya {lock.unlock (); // buka kunci} // tarik uang public void submoney (int money) {lock.lock (); if (count - money <0) {System.out.println ("Saldo Tidak Cukup"); ;} akhirnya {lock.unlock ();
Bagaimana efek operasinya?
Saldo Saldo Saldo yang Tidak Cukup: 0
Saldo Saldo Saldo yang Tidak Cukup: 0
1441792891934 Setoran: 100
Saldo Akun: 100
1441792892935Saved: 100
Saldo Akun: 200
1441792892954 Take Out: 100
Saldo Akun: 100
Efeknya mirip dengan dua metode pertama.
Jika kata kunci yang disinkronkan dapat memenuhi kebutuhan pengguna, gunakan disinkronkan karena dapat menyederhanakan kode. Jika Anda membutuhkan fungsi yang lebih maju, gunakan kelas Reentrantlock.
(5) Gunakan variabel lokal untuk mencapai sinkronisasi utas
Bank.java Code adalah sebagai berikut:
Paket ThreadTest; / ** * @Author WW * * / Bank Kelas Publik {Private Static Threadlocal <Integer> Count = New ThreadLocal <Integer> () {@override P Stub initial initiale () {// TODO Metode Auto return 0; ); ()- uang); hitung.
Efek Menjalankan:
Saldo Saldo Saldo yang Tidak Cukup: 0
Saldo Saldo Saldo yang Tidak Cukup: 0
1441794247939Saved: 100
Saldo Akun: 100
Keseimbangan yang tidak mencukupi
1441794248940Save: 100
Saldo Akun: 0
Saldo Akun: 200
Saldo Saldo Saldo yang Tidak Cukup: 0
1441794249941Saved: 100
Saldo Akun: 300
Setelah melihat efek operasi, saya bingung pada awalnya. Lihatlah prinsip Threadlocal:
Jika Anda menggunakan ThreadLocal untuk mengelola variabel, setiap utas menggunakan variabel akan mendapatkan salinan variabel, dan salinannya tidak tergantung satu sama lain, sehingga setiap utas dapat memodifikasi salinan variabelnya sendiri tanpa mempengaruhi utas lain. Sekarang saya mengerti. Ternyata setiap utas menjalankan salinan, yang berarti menghemat uang dan menarik uang adalah dua akun, dengan nama pengetahuan yang sama. Jadi efek di atas akan terjadi.
Mekanisme benang dan sinkronisasi
A.Threadlocal dan mekanisme sinkronisasi keduanya dimaksudkan untuk menyelesaikan masalah konflik akses dari variabel yang sama di multithreads
b. Yang pertama mengadopsi metode "ruang untuk waktu" dan yang terakhir mengadopsi metode "waktu untuk ruang" dan yang terakhir mengadopsi metode "waktu untuk ruang"
Sekarang saya mengerti. Masing -masing memiliki kelebihan dan kekurangannya sendiri dan memiliki skenario yang berlaku.