JavaRush /Blog Java /Random-MS /Concurrency di Jawa. Tutorial - Binaan selamat benang.
0xFF
Tahap
Донецк

Concurrency di Jawa. Tutorial - Binaan selamat benang.

Diterbitkan dalam kumpulan
Selepas melihat risiko utama menjalankan program selari (seperti atomicity atau visibility ), kami akan melihat beberapa reka bentuk kelas yang akan membantu kami mengelakkan perangkap yang disebutkan di atas. Sesetengah binaan ini mencipta objek selamat benang, membolehkan kami berkongsinya dengan selamat antara benang. Sebagai contoh, kita akan melihat objek tidak berubah dan tanpa kewarganegaraan. Pandangan lain akan menghalang urutan berbeza daripada mengubah suai data, seperti pembolehubah setempat utas. Anda boleh melihat semua kod sumber pada Github . 1. Objek Tidak Boleh Ubah Objek tidak boleh berubah mempunyai keadaan (mempunyai data yang mewakili keadaan objek), tetapi ia ditetapkan pada masa penciptaan dalam pembina, sebaik sahaja contoh objek telah dicipta dan keadaan tidak boleh diubah. Walaupun benang boleh silih berganti, objek masih mempunyai satu keadaan yang mungkin. Memandangkan semua medan adalah baca sahaja, tiada benang boleh menukar data objek. Oleh sebab itu, strim yang tidak boleh diubah sememangnya selamat untuk benang. Kelas Produk menunjukkan kelas tidak berubah. Ia mengisi semua medannya dalam pembina dan tiada satu pun daripadanya berubah: public final class Product { private final String id; private final String name; private final double price; public Product(String id, String name, double price) { this.id = id; this.name = name; this.price = price; } public String getId() { return this.id; } public String getName() { return this.name; } public double getPrice() { return this.price; } public String toString() { return new StringBuilder(this.id).append("-").append(this.name) .append(" (").append(this.price).append(")").toString(); } public boolean equals(Object x) { if (this == x) return true; if (x == null) return false; if (this.getClass() != x.getClass()) return false; Product that = (Product) x; if (!this.id.equals(that.id)) return false; if (!this.name.equals(that.name)) return false; if (this.price != that.price) return false; return true; } public int hashCode() { int hash = 17; hash = 31 * hash + this.getId().hashCode(); hash = 31 * hash + this.getName().hashCode(); hash = 31 * hash + ((Double) this.getPrice()).hashCode(); return hash; } } Dalam sesetengah kes, menjadikan medan muktamad tidak akan mencukupi. Sebagai contoh, kelas MutableProduct tidak boleh diubah, walaupun semua medan adalah muktamad: Mengapakah kelas di atas tidak boleh diubah? Sebabnya ialah kami membenarkan rujukan diambil daripada kelas. Medan ' kategori ' ialah rujukan boleh ubah, jadi setelah diterima, pelanggan boleh mengubah suainya. Untuk menggambarkan ini, pertimbangkan program berikut: Dan output konsol: Memandangkan medan 'kategori' boleh berubah dan diperoleh daripada objek, pelanggan telah mengubah suai senarai ini. Objek yang sepatutnya tidak berubah telah ditukar, menghasilkan keadaan baharu. Jika anda ingin mewakili kandungan senarai, anda boleh menggunakan perwakilan senarai tidak berubah: 2. Objek Tanpa Kewarganegaraan Objek tanpa kewarganegaraan adalah serupa dengan objek tidak berubah, tetapi dalam kes ini mereka tidak mempunyai keadaan, walaupun satu. Apabila objek ialah objek tanpa kewarganegaraan, ia tidak perlu mengekalkan sebarang data antara panggilan. Memandangkan tiada keadaan wujud, tiada benang boleh menjejaskan hasil benang lain dengan memanggil kaedah objek. Atas sebab ini, objek tanpa kewarganegaraan sememangnya selamat untuk benang. Kelas ProductHandler ialah contoh objek jenis ini. Ia mengandungi berbilang operasi pada objek Produk dan ia tidak menyimpan sebarang data antara panggilan. Hasil operasi adalah bebas daripada panggilan sebelumnya atau mana-mana data yang disimpan: Dalam kaedah sumCart, ProductHandler menukar senarai Produk kepada tatasusunan untuk digunakan dalam satu gelung bagi setiap untuk melelaran melalui semua elemen. Senarai iterator tidak selamat untuk thread dan mungkin membuang ConcurrentModificationException jika terdapat perubahan semasa lelaran. Bergantung pada keperluan anda, anda boleh memilih strategi yang berbeza . 3. Pembolehubah Setempat Thread Pembolehubah tempatan thread ialah pembolehubah yang ditakrifkan dalam thread. Tiada benang lain melihatnya dan tidak akan mengubahnya. Jenis pertama ialah pembolehubah tempatan. Dalam contoh di bawah, jumlah pembolehubah disimpan pada tindanan benang: public final class MutableProduct { private final String id; private final String name; private final double price; private final List categories = new ArrayList<>(); public MutableProduct(String id, String name, double price) { this.id = id; this.name = name; this.price = price; this.categories.add("A"); this.categories.add("B"); this.categories.add("C"); } public String getId() { return this.id; } public String getName() { return this.name; } public double getPrice() { return this.price; } public List getCategories() { return this.categories; } public List getCategoriesUnmodifiable() { return Collections.unmodifiableList(categories); } public String toString() { return new StringBuilder(this.id).append("-").append(this.name) .append(" (").append(this.price).append(")").toString(); } } public static void main(String[] args) { MutableProduct p = new MutableProduct("1", "a product", 43.00); System.out.println("Product categories"); for (String c : p.getCategories()) System.out.println(c); p.getCategories().remove(0); System.out.println("\nModified Product categories"); for (String c : p.getCategories()) System.out.println(c); } Product categories A B C Modified Product categories B C public List getCategoriesUnmodifiable() { return Collections.unmodifiableList(categories); } public class ProductHandler { private static final int DISCOUNT = 90; public Product applyDiscount(Product p) { double finalPrice = p.getPrice() * DISCOUNT / 100; return new Product(p.getId(), p.getName(), finalPrice); } public double sumCart(List cart) { double total = 0.0; for (Product p : cart.toArray(new Product[0])) total += p.getPrice(); return total; } } public double sumCart(List cart) { double total = 0.0; for (Product p : cart.toArray(new Product[0])) total += p.getPrice(); return total; } Perlu diingat bahawa jika anda mentakrifkan rujukan dan bukannya pembolehubah primitif dan mengembalikannya, ia akan meninggalkan sempadannya. Anda mungkin tidak tahu di mana pautan yang dikembalikan telah dibuat. Kod yang memanggil kaedah sumCart boleh menyimpannya dalam medan statik dan membolehkannya diakses oleh benang yang berbeza. Jenis kedua ialah kelas ThreadLocal . Kelas ini menyediakan storan bebas untuk setiap utas. Nilai yang disimpan dalam ThreadLocal tersedia untuk mana-mana kod pada urutan yang sama. Kelas ClientRequestId menunjukkan contoh penggunaan kelas ThreadLocale: Kelas ProductHandlerThreadLocal menggunakan ClientRequestId untuk mengembalikan ID yang dijana yang sama pada urutan yang sama: Apabila melaksanakan kaedah utama, output konsol akan menunjukkan ID yang berbeza untuk setiap utas. Contohnya: Jika anda akan menggunakan ThreadLocale, anda perlu menjaga beberapa risiko penggunaan apabila menggabungkan benang (seperti dalam aplikasi pelayan). Anda mungkin mendapat kebocoran memori atau kebocoran maklumat antara permintaan. Saya tidak akan menjelaskan perkara ini secara terperinci kerana... Artikel " Cara menembak diri sendiri dengan ThreadLocale " menunjukkan dengan baik bagaimana ini boleh berlaku. 4. Menggunakan penyegerakan Cara lain untuk menyediakan akses selamat benang kepada objek ialah melalui penyegerakan. Jika kita menyegerakkan semua akses kepada rujukan, maka hanya satu objek utas akan mengaksesnya pada masa tertentu. Kami akan membincangkan perkara ini dalam siaran akan datang. 5. Kesimpulan Kami melihat beberapa kaedah yang membolehkan anda membina objek mudah yang boleh diakses oleh berbilang benang. Adalah lebih sukar untuk menghalang ralat berbilang benang jika objek boleh mempunyai berbilang keadaan. Sebaliknya, jika objek hanya boleh mempunyai satu keadaan atau tiada, kita tidak perlu risau tentang berbilang benang mengakses objek pada masa yang sama. Asal ada di sini . public class ClientRequestId { private static final ThreadLocal id = new ThreadLocal () { @Override protected String initialValue() { return UUID.randomUUID().toString(); } }; public static String get() { return id.get(); } } public class ProductHandlerThreadLocal { //Same methods as in ProductHandler class public String generateOrderId() { return ClientRequestId.get(); } } T1 - 23dccaa2-8f34-43ec-bbfa-01cec5df3258 T2 - 936d0d9d-b507-46c0-a264-4b51ac3f527d T2 - 936d0d9d-b507-46c0-a264-4b51ac3f527d T3 - 126b8359-3bcc-46b9-859a-d305aff22c7e ...
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION