JavaRush /Blog Jawa /Random-JV /Concurrency ing Jawa. Tutorial - mbangun Utas-aman.
0xFF
tingkat
Донецк

Concurrency ing Jawa. Tutorial - mbangun Utas-aman.

Diterbitake ing grup
Sawise ndeleng risiko utama nglakokake program paralel (kayata atomicity utawa visibilitas ), kita bakal ndeleng sawetara desain kelas sing bakal mbantu nyegah pitfalls kasebut ing ndhuwur. Sawetara konstruksi kasebut nggawe obyek sing aman kanggo benang, supaya kita bisa bareng kanthi aman ing antarane benang. Minangka conto, kita bakal ndeleng obyek sing ora bisa diganti lan tanpa negara. Tampilan liyane bakal nyegah thread beda saka ngowahi data, kayata variabel lokal thread. Sampeyan bisa ndeleng kabeh kode sumber ing Github . 1. Obyek sing ora bisa diganti Obyek sing ora bisa diganti duwe negara (duwe data sing makili kahanan obyek), nanging disetel ing wektu nggawe ing konstruktor, yen conto obyek wis digawe lan negara ora bisa diganti. Senajan Utas bisa sulih, obyek isih duwe siji kahanan. Amarga kabeh kolom mung diwaca, ora ana thread sing bisa ngganti data obyek kasebut. Amarga iki, stream sing ora bisa diganti pancen aman kanggo benang. Kelas Product nduduhake kelas immutable. Isi kabeh kolom ing konstruktor lan ora ana sing ngganti: 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; } } Ing sawetara kasus, nggawe lapangan final ora cukup. Contone, kelas MutableProduct ora bisa diganti, sanajan kabeh lapangan final: Napa kelas ing ndhuwur ora bisa diganti? Alesane yaiku kita ngidini referensi dijupuk saka kelas. Bidang ' kategori ' minangka referensi sing bisa diowahi, dadi yen ditampa, klien bisa ngowahi. Kanggo ilustrasi iki, nimbang program ing ngisor iki: Lan output console: Wiwit lapangan 'kategori' mutable lan dijupuk saka obyek, klien wis diowahi dhaftar iki. Obyek sing kudune immutable wis diganti, asil ing negara anyar. Yen sampeyan pengin makili isi dhaftar, sampeyan bisa nggunakake perwakilan dhaftar immutable: 2. Obyek Stateless Obyek stateless padha karo obyek immutable, nanging ing kasus iki padha ora duwe negara, malah siji. Nalika obyek minangka obyek tanpa negara, ora kudu nyimpen data ing antarane telpon. Amarga ora ana negara, ora ana thread sing bisa mengaruhi asil thread liyane kanthi nelpon metode obyek. Mulane, obyek stateless pancen aman kanggo benang. Kelas ProductHandler minangka conto obyek jinis iki. Isine sawetara operasi ing obyek Product, lan ora nyimpen data ing antarane telpon. Asil operasi punika independen saka telpon sadurungé utawa data sing disimpen: Ing cara sumCart, ProductHandler Ngonversi dhaftar Product kanggo Uploaded kanggo nggunakake ing saben daur ulang kanggo iterate liwat kabeh unsur. Dhaptar iterator ora aman lan bisa mbuwang ConcurrentModificationException yen ana owah-owahan sajrone pengulangan. Gumantung saka kabutuhan sampeyan, sampeyan bisa milih strategi sing beda . 3. Variabel Lokal Utas Variabel lokal Utas yaiku variabel sing ditetepake sajrone benang. Ora ana benang liyane sing ndeleng lan ora bakal ngganti. Jinis pisanan yaiku variabel lokal. Ing conto ing ngisor iki, total variabel disimpen ing tumpukan 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; } Mung elinga yen sampeyan nemtokake referensi tinimbang variabel primitif lan bali, bakal ninggalake watese. Sampeyan bisa uga ora ngerti ngendi link bali digawe. Kode sing nyebut cara sumCart bisa nyimpen ing kolom statis lan ngidini supaya bisa diakses dening thread beda. Tipe kapindho yaiku kelas ThreadLocal . Kelas iki nyedhiyakake panyimpenan mandiri kanggo saben thread. Nilai sing disimpen ing ThreadLocal kasedhiya kanggo kode apa wae ing thread sing padha. Kelas ClientRequestId nuduhake conto panggunaan kelas ThreadLocale: ProductHandlerThreadLocal kelas nggunakake ClientRequestId kanggo bali ID kui padha ing thread padha: Nalika nglakokaké cara utama, output console bakal nuduhake ID beda kanggo saben thread. Contone: Yen sampeyan arep nggunakake ThreadLocale, sampeyan kudu ngurus sawetara risiko panggunaan nalika nggabungake thread (kaya ing aplikasi server). Sampeyan bisa uga ngalami bocor memori utawa bocor informasi ing antarane panjaluk. Aku ora bakal rinci babagan iki amarga ... Artikel " Carane njupuk dhewe ing sikil nganggo ThreadLocale " nduduhake carane iki bisa kedadeyan. 4. Nggunakake sinkronisasi Cara liya kanggo nyedhiyani akses thread-aman kanggo obyek liwat sinkronisasi. Yen kita nyinkronake kabeh akses menyang referensi, mung siji obyek thread bakal ngakses ing wektu tartamtu. Kita bakal ngrembug babagan iki ing kiriman sabanjure. 5. Kesimpulan Kita nyawang sawetara cara sing ngidini sampeyan mbangun obyek sing prasaja sing bisa diakses kanthi pirang-pirang benang. Iku luwih angel kanggo nyegah kasalahan multi-Utas yen obyek bisa duwe sawetara negara. Ing tangan liyane, yen obyek mung bisa duwe siji negara utawa ora ana, kita ora perlu kuwatir bab sawetara Utas ngakses obyek ing wektu sing padha. Asli kene . 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 ...
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION