Çizgi Roman: Kız arkadaşına singleton modunun ne olduğunu nasıl açıklayabilirim? | Teknik Başlıklar

Sorumlu Editör | Wu Xingling

Bu makale, Ranhua Programming'den alınan yetkilendirme ile yeniden üretilmiştir (ID: mhcoding)

Hafta sonu İşçi Bayramı yaklaşıyor Kız arkadaşım nereye gideceğini bilmedi ve hala çeşitli stratejiler araştırıyor. Yanımda bir kitap okuyordum ve sessizce cüzdanımı incitiyordum. Aniden kız arkadaşım sormaya başladı:

Singleton nedir

Tek alt mod olarak da adlandırılan tekli mod, yaygın olarak kullanılan bir yazılım tasarım modudur . Bu deseni uygularken, tekli nesnenin sınıfı yalnızca bir örneğin var olduğundan emin olmalıdır.

Çoğu zaman, tüm sistemin yalnızca tek bir küresel nesneye sahip olması gerekir, bu da sistemin genel davranışını koordine etmemize yardımcı olur. Örneğin, bir sunucu programında, sunucunun konfigürasyon bilgisi bir dosyada depolanır ve konfigürasyon verileri tek tip bir nesne tarafından tek tip olarak okunur ve daha sonra hizmet sürecindeki diğer nesneler, konfigürasyon bilgilerini tekli nesne aracılığıyla alır. Bu yaklaşım, karmaşık ortamlarda konfigürasyon yönetimini basitleştirir.

Kod geliştirme için, bir sınıfın aynı anda yalnızca bir örnek nesneye sahip olduğu duruma tekli ad denir. Öyleyse, bir sınıfın yalnızca bir nesneye sahip olabileceğinden nasıl emin olunur?

Nesne yönelimli düşüncede nesnelerin bir sınıfın kurucusu aracılığıyla oluşturulabileceğini ve bellek yeterli olduğu sürece herhangi bir sayıda nesnenin oluşturulabileceğini biliyoruz.

Bu nedenle, belirli bir sınıfı yalnızca bir singleton nesneyle sınırlamak istiyorsanız, onun yapıcısı üzerinde çok çalışmanız gerekir.

Nesne tekli modunu uygulama fikri şudur:

1. Bir sınıf, nesneye bir başvuru (her zaman aynı) ve örneği elde etmek için bir yöntem (genellikle getInstance adını kullanan statik bir yöntem olmalıdır) döndürebilir;

2. Bu yöntemi çağırdığımızda, sınıf tarafından tutulan referans boş değilse, bu referansı geri döndürün.Sınıfın tuttuğu referans boşsa, sınıfın bir örneğini oluşturun ve örneğin referansını sınıfın tuttuğu referansa atayın;

3. Aynı zamanda, bu sınıfın yapıcısını da özel bir yöntem olarak tanımlıyoruz, böylece başka yerlerdeki kod, bu sınıfın yapıcısını çağırarak bu sınıfın nesnesini başlatamaz ve sınıfı yalnızca bu sınıf tarafından sağlanan statik yöntemle elde edebilir. Tek örneği.

public class Singleton { özel statik Singleton örneği; özel Singleton () {} public static Singleton getInstance () { eğer (örnek == null) { örnek = new Singleton (); } dönüş örneği; } }

Yukarıdaki Java kodu basit bir tekli model uygular. İnşaat yöntemini özel olarak tanımlıyoruz ve ardından sınıfın bir örneğinin zaten var olup olmadığını belirleyen ve varsa doğrudan geri dönen bir getInstance yöntemi sağlıyoruz. Eğer yoksa, bir tane oluşturun ve geri dönün.

İş parçacığı güvenli tekli

Çin'de, bir eşiniz olmasını istiyorsanız, hem erkeklerin hem de kadınların, ilgili ev kayıt defterleriyle birlikte bir sertifika almak için Sivil İşler Bürosuna gitmeleri gerekir. Sivil İşler Bürosu personeli önce sistemdeki her iki tarafın medeni durumunu kontrol edecek ve ardından kayıt işlemlerinden geçecektir. Başarılı tek eşli kayıt için ön koşul, eşzamanlılık sorunu olmayacak olmasıdır.

Bir erkeğin aynı anda iki farklı kadınla kayıt olabileceği varsayılırsa, personel sorduğunda evli olmama olasılığı vardır ve daha sonra iki evlilik için kayıt yaptırabilir. Tabi bu durum gerçek hayatta imkansızdır.

Ancak programda çok iş parçacıklı bir sahne olduğunda bu durum çok yaygındır. Tıpkı yukarıdaki kod gibi.

İki iş parçacığı aynı anda if (örnek == null) satırına kadar yürütülürse, bu karar geçecektir ve ardından her biri örnek = new Singleton () yürütecektir; ve her biri bir örnek döndürür, bu sırada birden fazla örnek oluşturulur , Singleton garantisi yoktur!

Yukarıdaki singleton uygulamasına genellikle tembel adam modu adı verilir.Tembel adam, yalnızca nesneye ihtiyaç duyulduğunda nesnenin üretilmesini ifade eder (getInstance yöntemi çağrıldığında oluşturulur).

Yukarıdaki tembel adam modu iş parçacığı güvenli değildir, bu nedenle günlük geliştirmede kullanılması önerilmez. Bu modele dayanarak, aşağıdaki gibi iş parçacığı güvenli bir tekli uygulayabiliriz:

public class Singleton { özel statik Singleton örneği; özel Singleton () {} genel statik senkronize Singleton getInstance () { eğer (örnek == null) { örnek = new Singleton (); } dönüş örneği; } }

GetInstance yöntemine senkronize edilenler eklenerek eşzamanlılık sorunu kilitlenerek çözülür. Bu uygulama ile birden fazla nesnenin yaratılması sorunu ortaya çıkmayacaktır.

Çift kontrol kilidi

Yukarıdaki iş parçacığı güvenli tembel yazma, birden çok iş parçacığında iyi çalışabilir, ancak maalesef bu yaklaşım çok verimsizdir, çünkü eşzamanlılık kontrolü yalnızca ilk başlatma için gereklidir. Senkronizasyon gerekmez.

Aslında, yukarıdaki kodun bir miktar optimizasyonunu yapabiliriz, çünkü tembel modda, senkronize edilmiş bir senkronizasyon yöntemini tanımlamak için kullanılır.Senkronize'nin aynı zamanda senkronize edilmiş bir kod bloğu tanımlamak için de kullanılabileceğini biliyoruz ve senkronize edilmiş kod bloğunun ayrıntı düzeyi, senkronize yönteminkinden daha küçüktür, dolayısıyla verimlilik Daha yüksek olacak. Aşağıdaki kod gibi:

public class Singleton { özel uçucu statik Singleton singleton; özel Singleton () {} public static Singleton getSingleton () { eğer (singleton == null) { senkronize (Singleton.class) { eğer (singleton == null) { singleton = yeni Singleton (); } } } tekil dönüş; } }

Yukarıdaki formda, nesne sadece singleton == null olduğunda kilitlenerek oluşturulabilir. Singleton! = Null ise, sadece eşzamanlılık kontrolü olmadan doğrudan dönün. Verimliliği büyük ölçüde artırın.

Yukarıdaki koddan da görebileceğiniz gibi, aslında singleton == null yargısı tüm süreçte iki kez gerçekleştirilir, bu nedenle bu yönteme "çift kontrol kilidi" denir.

İkili kontrol kilidinin uygulanmasında, statik üye değişkeni tekinin, başlatılmasının atomikliğini sağlamak için uçucu tarafından değiştirilmesi gerektiğine dikkat etmek önemlidir, aksi takdirde, başlatılmamış bir nesneye atıfta bulunulabilir.

Neden çift kontrol kilitleri statik üye değişkeni tekliyi değiştirmek için uçucu kullanmaya ihtiyaç duyar? Neden iş parçacığı güvenli tembel adamlara ihtiyaç duymuyorsunuz? Bu konuda, takip eden makaleler derinlemesine açıklanacaktır.

Aç adam modu

Daha önce bahsedilen tembel adam modu aslında bir Lazy-Loading düşüncesi uygulamasıdır.Bu uygulamanın büyük bir avantajı vardır, yani sadece gerçekten kullanıldığında yaratılır ve kullanılmazsa asla yaratılmayacaktır. , Bu gereksiz masrafları önler.

Bununla birlikte, bu yaklaşımın aslında küçük bir dezavantajı vardır, yani ilk kullanıldığında, başlatılması gerekir ki bu nispeten zaman alıcı olabilir. Belli bir nesnenin kullanılacağı biliniyorsa, aslında aç bir adamın uygulaması benimsenebilir.

Sözde aç adam, önceden hazırlanmalı ve ihtiyacınız olduğunda size vermelidir. Bu, günlük hayatta daha yaygın olan "önce bir bilet al sonra otobüse bin" ve normal prosedürlerden geçmek.

Aşağıdaki kod gibi, aç adam modu:

public class Singleton { özel statik Singleton örneği = new Singleton (); özel Singleton () {} public static Singleton getInstance () { dönüş örneği; } }

Veya aşağıdaki kod, aç adam varyantı:

public class Singleton { özel Singleton örneği = boş; statik { örnek = new Singleton (); } özel Singleton () {} public static Singleton getInstance () { this.instance'ı iade edin; } }

Aslında, yukarıdaki iki kod parçası arasında önemli bir fark yoktur, her ikisi de sınıf nesnelerini statik aracılığıyla başlatır. Aç adam kipindeki statik değişkenler, sınıf yüklenirken başlatılır. Hungry man varyantındaki statik kod bloğu da sınıf yüklenirken çalıştırılacaktır.

Yukarıdaki iki aç adam yöntemi, sınıf başlatıldığında örneğin başlatılabilmesini sağlamak için aslında statik üye değişkenleri tanımlar.

Sınıfın başlatılması ClassLoader tarafından yapıldığından, bu aslında ClassLoader'ın iş parçacığı güvenlik mekanizmasını kullanır. ClassLoader'ın loadClass yöntemi, sınıfı yüklerken senkronize edilmiş anahtar sözcüğü kullanır. Tam da bu nedenle, yeniden yazılmadığı sürece, bu yöntem tüm yükleme işlemi boyunca varsayılan olarak senkronize edilir (iş parçacığı güvenli)

Yukarıdaki iki aç adam yöntemine ek olarak, bunu calss başlatma yardımıyla uygulamanın başka bir yolu vardır, yani statik bir iç sınıf aracılığıyla uygulanan bir tekil:

public class Singleton { özel statik sınıf SingletonHolder { özel statik final Singleton INSTANCE = new Singleton (); } özel Singleton () {} public static final Singleton getInstance () { SingletonHolder.INSTANCE döndür; } }

Daha önce bahsedilen aç adam modunda, Singleton sınıfı yüklü olduğu sürece örnek başlatılacaktır.

Bu şekilde, Singleton sınıfı yüklenir ve örneğin başlatılması gerekmez. SingletonHolder sınıfı aktif olarak kullanılmadığından, yalnızca getInstance yöntemi çağrıldığında, örneği başlatmak için SingletonHolder sınıfı görüntülenir.

Statik dahili sınıfların kullanımı ve iş parçacığı güvenliğini sağlamak için sınıf yükleyicinin kullanılması, aç adam moduna benzer, ancak kıyaslandığında büyük avantajları olan tembel adam modunu hesaba katan Tembel Yükleme işlevine sahiptir.

Singleton imhası

Daha önce de belirtildiği gibi, uyguladığımız singletonda, yapıcı yöntemini harici çağrılardan kaçınmak için özel bir yöntem olarak ayarlamak önemli bir öncüldür. Bununla birlikte, özel bir müteahhidi dışarıdan aramak gerçekten imkansız mı?

Aslında öyle değil, sınıfta özel yöntemleri yansıtma yoluyla çağırabiliriz ve inşa yöntemi de bir istisna değildir, bu nedenle yansıtma yoluyla singletonu yok edebiliriz.

Bu duruma ek olarak göz ardı edilmesi daha kolay olan başka bir durum daha var, yani nesnenin serileştirilmesi ve serileştirilmesinin kaldırılması da tekliyi yok edecektir.

Örneğin, seri durumdan çıkarma için ObjectInputStream kullanılırken, ObjectInputStream'in readObject'i tarafından bir nesne oluşturma sürecinde, aslında yansıma yoluyla argümansız yapı yöntemini çağırarak yeni bir nesne oluşturulacaktır.

Bu nedenle, bir tekli nesneyi sıralı hale getirirken ve serisini kaldırırken, böyle bir tekil nesnenin yok olma olasılığını göz önünde bulundurmalısınız.

Bu sorun, Singleton sınıfında readResolve tanımlanarak çözülebilir:

/ ** * Tekli tonu gerçekleştirmek için çift kontrol kilidi yöntemini kullanın * / public class Singleton, Serializable { özel uçucu statik Singleton singleton; özel Singleton () {} public static Singleton getSingleton () { eğer (singleton == null) { senkronize (Singleton.class) { eğer (singleton == null) { singleton = yeni Singleton (); } } } tekil dönüş; } private Object readResolve () { tekil dönüş; } }

Numaralandırma singleton gerçekleştirir

StakcOverflow'da, Java'da bir tekil modeli uygulamanın etkili bir yolu nedir? tartışma:

Yukarıda gösterildiği gibi, en yüksek oy oranına sahip cevap: numaralandırma kullanın.

Katılımcılar, Joshua Bloch tarafından "Etkili Java" da açıkça ifade edilen görüşleri aktardılar:

Bir singleton uygulamak için numaralandırma kullanma yöntemi yaygın olarak benimsenmemiş olsa da, tek öğeli numaralandırma türü Singleton'u uygulamak için en iyi yöntem haline gelmiştir.

Tekillerin kullanımını ve bazı olası tuzakları gerçekten anlıyorsanız, aynı sonucu elde edebilirsiniz, yani tekil tonları elde etmek için numaralandırma kullanmak iyi bir yoldur.

Numaralandırma, tekli:

public enum Singleton { INSTANCE; public void what'sMethod () { } }

Yukarıda, çok basit bir tekli gerçekleştirilmiştir: Kod satırlarının sayısından, öncekilerden daha akıcıdır ve aynı zamanda iş parçacığı açısından güvenlidir.

Bunlar aslında bizi bu yöntemin optimal olduğuna ikna etmek için yeterli değil. Ancak çok önemli bir neden daha var: Numaralandırma, serileştirmenin tekliyi yok edeceği sorununu çözebilir.

Bu bilgi noktasına başvurabilirsiniz

"Neden tekilleri uygulamak için numaralandırma kullanmanızı öneriyorum"

Bu yazıda numaralandırma ve tekilleştirme ile ilgili tüm bilgi noktaları detaylı olarak açıklanmıştır.

Tekli yapmak için Senkronize'yi kullanmayın

Yukarıda bahsedilen tüm yöntemler, iş parçacığı açısından güvenli oldukları sürece, aslında doğrudan veya dolaylı olarak senkronize edilirler.Eğer senkronize edilemiyorsa, bir tekli nasıl uygulanır?

Kilit kullanılsın mı? Tabii ki bu iyi, ama aslında hala kilitleniyor Kilitlemeden kullanmanın bir yolu var mı?

Cevap evet, bu CAS. CAS iyimser bir kilitleme teknolojisidir.Çok sayıda iş parçacığı aynı değişkeni aynı anda güncellemek için CAS'ı kullanmaya çalıştığında, yalnızca bir iş parçacığı değişkenin değerini güncelleyebilir ve diğer iş parçacıkları başarısız olur. Başarısız olan iş parçacığı askıya alınmaz, ancak Bu yarışmada başarısız olduğum ve tekrar deneyebileceğim söylendi.

JDK1.5'e yeni eklenen java.util.concurrent (J.U.C), CAS'a dayanmaktadır. Senkronize engelleme algoritmalarıyla karşılaştırıldığında, CAS, engellemeyen algoritmaların yaygın bir uygulamasıdır. Bu nedenle J.U.C, performans açısından büyük ölçüde geliştirildi.

CAS (AtomicReference) ile tekli modu gerçekleştirin:

public class Singleton { özel statik final AtomicReference < Singleton > ANLIK = new AtomicReference < Singleton > (); özel Singleton () {} public static Singleton getInstance () { için (;;) { Singleton singleton = INSTANCE.get (); eğer (null! = singleton) { tekil dönüş; } singleton = yeni Singleton (); eğer (INSTANCE.compareAndSet (null, singleton)) { tekil dönüş; } } } }

CAS kullanmanın avantajı, iş parçacığı güvenliğini sağlamak için geleneksel kilit mekanizmasını kullanmaya gerek olmamasıdır.CAS, meşgul beklemeye dayalı bir algoritmadır ve temeldeki donanımın uygulanmasına dayanır. Kilitle karşılaştırıldığında, ek iş parçacığı değiştirme ve engelleme tüketimi yoktur ve daha büyük Paralellik derecesi.

CAS'ı singleton uygulamak için kullanmak sadece bir fikirdir, okuyucuların CAS ve singleton bilgisine hakim olmasına yardımcı olmak için onu genişletin, kodda kullanmayın! ! ! Bu kodda aslında optimizasyon için çok yer var. Akıllı sen, yukarıdaki kodun gizli tehlikelerini biliyor musun?

5G ticari olarak mevcut olduğunda, akıllı şehrimiz nasıl görünecek?
önceki
@ 996 Programcı, YBÜ'ye gitmeye gerçekten gücünüz yetmez!
Sonraki
Jack Ma: Tencent, Alinin büyüme ortağıdır; Huaweinin 20.000 CNBG çalışanı Yu Chengdonga "döndü"
JavaScript'i değiştirin! Python, Stack Overflow'un en çok sorgulanan programlama dili olur
Trafik kraldır, programcılar 8 saniye prensibini nasıl bozabilir? | Teknik Başlıklar
Mozilla, bir Nesnelerin İnterneti platformu olan WebThings'i başlattı! | Geek Başlıklar
Karısı bebeğe sarıldı, kocası "iyi kız" dedi, bebeğin tepkisi şaşırtıcıydı
"Xiao Luo" nun oğlu, uluslararası kampüs futbol turnuvasına katılmak için Çin'e geldi.
Programcılar becerilerini düşük seviyeli olarak nasıl gösterirler? | Teknik Başlıklar
Liu Shishi, altı jin ağırlığında bir oğlu doğurdu ve koğuşa transfer edildi. Wu Qilong, onaylayan bir mektup yayınladı: Teşekkürler
Park Yoo-chun pozitif çıktı ve yüzüne vurdu
Tesla'nın yeni otopilot çipi en güçlüsü mü? Nvidia geri döndü! | Geek Başlıklar
Hu Ge'nin başarılı dönüşümü, yeni filmi "The Gathering at South Station" Cannes Film Festivali'ne aday gösterildi.
Microsoft GitHub 996'ya şiddetle direniyor!
To Top