Birisi bana bir örnek ile senkronize blok üzerinden senkronize yöntem avantajı söyleyebilir?
Birisi bana bir örnek ile senkronize blok üzerinden senkronize yöntem avantajı söyleyebilir?
Yanıtlar:
Herkes bana senkronize yöntem avantajlı senkronize blok üzerinde bir örnek söyleyebilir? Teşekkürler.
Blok üzerinde senkronize yöntem kullanmanın açık bir avantajı yoktur.
Belki de tek (ama buna bir avantaj demezdim) nesne referansını eklemenize gerek yok this
.
Yöntem:
public synchronized void method() { // blocks "this" from here....
...
...
...
} // to here
Blok:
public void method() {
synchronized( this ) { // blocks "this" from here ....
....
....
....
} // to here...
}
Görmek? Hiçbir avantajı yok.
Bloklar yapmak yöntemi senkronize tüm nesneyi kilitlemek oysa kilidi gibi başka bir nesneyi kullanabilirsiniz çünkü çoğunlukla esneklik içinde olsa yöntemlerine göre avantajları vardır.
Karşılaştırmak:
// locks the whole object
...
private synchronized void someInputRelatedWork() {
...
}
private synchronized void someOutputRelatedWork() {
...
}
vs.
// Using specific locks
Object inputLock = new Object();
Object outputLock = new Object();
private void someInputRelatedWork() {
synchronized(inputLock) {
...
}
}
private void someOutputRelatedWork() {
synchronized(outputLock) {
...
}
}
Ayrıca yöntem büyürse, senkronize edilmiş bölümü ayrı tutabilirsiniz:
private void method() {
... code here
... code here
... code here
synchronized( lock ) {
... very few lines of code here
}
... code here
... code here
... code here
... code here
}
synchronized
blok iki talimatları kullanılarak uygulanır, monitorenter
ve monitorexit
, artı sağlar istisna işleyicisi monitorexit
bile istisnai durumlarda denir. Bir synchronized
yöntem kullanılırken tüm bunlar kaydedilir .
Tek gerçek fark, senkronize edilmiş bir bloğun hangi nesne üzerinde senkronize edileceğini seçebilmesidir. Senkronize yöntem yalnızca 'this'
(veya senkronize sınıf yöntemi için karşılık gelen Sınıf örneği) kullanabilir. Örneğin, bunlar anlamsal olarak eşdeğerdir:
synchronized void foo() {
...
}
void foo() {
synchronized (this) {
...
}
}
İkincisi daha esnektir, çünkü genellikle bir üye değişken olan herhangi bir nesnenin ilişkili kilidi için rekabet edebilir . Aynı zamanda daha ayrıntılıdır, çünkü bloktan önce ve sonra eşzamanlı kod çalıştırabilirsiniz, ancak yine de yöntem içinde. Tabii ki, eşzamanlı kodu ayrı senkronize olmayan yöntemlere yeniden düzenleyerek eşitlenmiş bir yöntemi kolayca kullanabilirsiniz. Kodu daha anlaşılır yapan hangisi olursa kullanın.
Artıları:
Eksileri:
Artıları:
Eksileri:
Şahsen ben sadece senkronizasyon ihtiyacı olan şeylere odaklanmış sınıflarla senkronize yöntemler kullanmayı tercih ederim. Bu sınıf mümkün olduğunca küçük olmalı ve bu nedenle senkronizasyonu gözden geçirmek kolay olmalıdır. Diğerleri senkronizasyonu önemsememelidir.
Ana fark senkronize bir blok kullanırsanız dışında bir nesne üzerinde kilit olabilmesidir bu çok daha esnek olmasını sağlar.
Bir mesaj kuyruğunuz ve birden çok mesaj üreticisi ve tüketiciniz olduğunu varsayın. Üreticilerin birbirine müdahale etmesini istemiyoruz, ancak tüketicilerin üreticileri beklemek zorunda kalmadan mesaj alabilmesi gerekiyor. Bu yüzden sadece bir nesne yaratıyoruz
Object writeLock = new Object();
Ve bundan sonra bir üretici her yeni mesaj eklemek istediğinde bunu kilitleriz:
synchronized(writeLock){
// do something
}
Böylece tüketiciler hala okuyabilir ve üreticiler kilitlenir.
Senkronize yöntem
Senkronize yöntemlerin iki etkisi vardır.
İlk olarak, bir iş parçacığı bir nesne için eşzamanlı bir yöntem yürütürken, ilk iş parçacığı nesne ile yapılana kadar aynı nesne bloğu için eşzamanlı yöntemleri çağıran diğer tüm iş parçacıkları (yürütmeyi askıya alma).
İkincisi, senkronize edilmiş bir yöntem çıktığında, aynı nesne için senkronize edilmiş bir yöntemin daha sonraki herhangi bir çağrılmasıyla otomatik olarak gerçekleşmeden önce ilişki kurar. Bu, nesnenin durumundaki değişikliklerin tüm iş parçacıkları tarafından görülebilir olmasını sağlar.
Yapıcıların senkronize edilemeyeceğini unutmayın - bir yapıcı ile senkronize edilmiş anahtar kelimeyi kullanmak bir sözdizimi hatasıdır. Yapıcıları senkronize etmek mantıklı değildir, çünkü yalnızca bir nesneyi oluşturan iş parçacığının inşa edilirken ona erişmesi gerekir.
Senkronize Açıklama
Senkronize yöntemlerden farklı olarak, senkronize ifadeler kendinden kilit sağlayan nesneyi belirtmelidir: Çoğu zaman bunu bir liste veya haritaya erişimi senkronize etmek için kullanıyorum ancak nesnenin tüm yöntemlerine erişimi engellemek istemiyorum.
S: İçsel Kilitler ve Eşitleme Eşitleme, iç kilit veya monitör kilidi olarak bilinen bir iç varlık etrafında oluşturulur. (API spesifikasyonu genellikle bu varlığı basitçe bir "monitör" olarak ifade eder.) İçsel kilitler senkronizasyonun her iki yönünde de rol oynar: bir nesnenin durumuna özel erişim sağlamak ve görünürlük için gerekli olan ilişkiden önce ilişkiler kurmak.
Her nesnenin kendisiyle ilişkilendirilmiş kendinden kilit vardır. Kural olarak, bir nesnenin alanlarına özel ve tutarlı erişime ihtiyaç duyan bir iş parçacığının, nesneye erişmeden önce kendinden kilit alması ve onlarla iş bitince iç kilidi serbest bırakması gerekir. Bir ipliğin, kilidi edindiği ve kilidi serbest bıraktığı zaman arasında içsel kilide sahip olduğu söylenir. Bir iş parçacığının kendiliğinden bir kilidi olduğu sürece, başka hiçbir iş parçacığı aynı kilidi alamaz. Diğer iş parçacığı kilidi almaya çalıştığında engellenir.
package test;
public class SynchTest implements Runnable {
private int c = 0;
public static void main(String[] args) {
new SynchTest().test();
}
public void test() {
// Create the object with the run() method
Runnable runnable = new SynchTest();
Runnable runnable2 = new SynchTest();
// Create the thread supplying it with the runnable object
Thread thread = new Thread(runnable,"thread-1");
Thread thread2 = new Thread(runnable,"thread-2");
// Here the key point is passing same object, if you pass runnable2 for thread2,
// then its not applicable for synchronization test and that wont give expected
// output Synchronization method means "it is not possible for two invocations
// of synchronized methods on the same object to interleave"
// Start the thread
thread.start();
thread2.start();
}
public synchronized void increment() {
System.out.println("Begin thread " + Thread.currentThread().getName());
System.out.println(this.hashCode() + "Value of C = " + c);
// If we uncomment this for synchronized block, then the result would be different
// synchronized(this) {
for (int i = 0; i < 9999999; i++) {
c += i;
}
// }
System.out.println("End thread " + Thread.currentThread().getName());
}
// public synchronized void decrement() {
// System.out.println("Decrement " + Thread.currentThread().getName());
// }
public int value() {
return c;
}
@Override
public void run() {
this.increment();
}
}
Senkronize yöntem, blok ve senkronizasyon olmadan farklı çıkışları çapraz kontrol edin.
Not: statik senkronize yöntemler ve bloklar Class nesnesinde çalışır.
public class MyClass {
// locks MyClass.class
public static synchronized void foo() {
// do something
}
// similar
public static void foo() {
synchronized(MyClass.class) {
// do something
}
}
}
Java derleyici kaynak kodunuzu bayt koduna dönüştürdüğünde, senkronize yöntemleri ve senkronize blokları çok farklı şekilde işler.
JVM senkronize bir yöntem yürüttüğünde, yürütme iş parçacığı yöntemin method_info yapısının ACC_SYNCHRONIZED bayrağı ayarlanmış olduğunu tanımlar, sonra otomatik olarak nesnenin kilidini alır, yöntemi çağırır ve kilidi serbest bırakır. Bir istisna oluşursa, iplik otomatik olarak kilidi serbest bırakır.
Öte yandan, bir yöntem bloğunun senkronize edilmesi, JVM'nin bir nesnenin kilit ve istisna yönetimini elde etmek için yerleşik desteğini atlar ve işlevselliğin açıkça bayt kodunda yazılmasını gerektirir. Senkronize bloğu olan bir yöntemin bayt kodunu okursanız, bu işlevi yönetmek için bir düzineden fazla ek işlem görürsünüz.
Bu, hem senkronize yöntem hem de senkronize blok oluşturmak için çağrıları gösterir:
public class SynchronizationExample {
private int i;
public synchronized int synchronizedMethodGet() {
return i;
}
public int synchronizedBlockGet() {
synchronized( this ) {
return i;
}
}
}
synchronizedMethodGet()
Yöntem aşağıdaki bayt kodu oluşturur:
0: aload_0
1: getfield
2: nop
3: iconst_m1
4: ireturn
İşte synchronizedBlockGet()
yöntemdeki bayt kodu :
0: aload_0
1: dup
2: astore_1
3: monitorenter
4: aload_0
5: getfield
6: nop
7: iconst_m1
8: aload_1
9: monitorexit
10: ireturn
11: astore_2
12: aload_1
13: monitorexit
14: aload_2
15: athrow
Senkronize yöntem ve blok arasındaki önemli bir fark, Senkronize blok genellikle kilit kapsamını azaltır. Kilidin kapsamı performansla ters orantılı olduğundan, kodun sadece kritik bölümünü kilitlemek her zaman daha iyidir. Senkronize blok kullanmanın en iyi örneklerinden biri, bütünü kilitlemek yerine Singleton deseninde çift kontrollü kilitlemegetInstance()
yöntemi yalnızca Singleton örneği oluşturmak için kullanılan kodun kritik bölümünü kilitleriz. Kilitleme sadece bir veya iki kez gerektiğinden bu, performansı önemli ölçüde artırır.
Senkronize yöntemleri kullanırken, hem statik senkronize hem de statik olmayan senkronize yöntemleri karıştırırsanız daha dikkatli olmanız gerekir.
monitorenter
ve monitorexit
kodu çalıştırmadan önce ekleyecektir .
Çoğu zaman bunu bir liste veya haritaya erişimi senkronize etmek için kullanıyorum ancak nesnenin tüm yöntemlerine erişimi engellemek istemiyorum.
Aşağıdaki kodda, listeyi değiştiren bir iş parçacığı, haritayı değiştiren bir iş parçacığının beklemesini engellemez. Yöntemler nesne üzerinde senkronize edilmiş olsaydı, yaptıkları değişiklikler çakışmasa bile her yöntemin beklemesi gerekirdi.
private List<Foo> myList = new ArrayList<Foo>();
private Map<String,Bar) myMap = new HashMap<String,Bar>();
public void put( String s, Bar b ) {
synchronized( myMap ) {
myMap.put( s,b );
// then some thing that may take a while like a database access or RPC or notifying listeners
}
}
public void hasKey( String s, ) {
synchronized( myMap ) {
myMap.hasKey( s );
}
}
public void add( Foo f ) {
synchronized( myList ) {
myList.add( f );
// then some thing that may take a while like a database access or RPC or notifying listeners
}
}
public Thing getMedianFoo() {
Foo med = null;
synchronized( myList ) {
Collections.sort(myList);
med = myList.get(myList.size()/2);
}
return med;
}
Eşzamanlı bloklarla, birden fazla eşzamanlayıcıya sahip olabilirsiniz, böylece aynı anda birden çok eşzamanlı ancak çakışmasız şey devam edebilir.
Senkronize yöntemler yansıma API'sini kullanarak kontrol edilebilir. Bu, modeldeki tüm yöntemler senkronize gibi bazı sözleşmeleri test etmek için yararlı olabilir .
Aşağıdaki snippet, Hashtable'ın tüm senkronize yöntemlerini yazdırır:
for (Method m : Hashtable.class.getMethods()) {
if (Modifier.isSynchronized(m.getModifiers())) {
System.out.println(m);
}
}
Senkronize bloğu kullanma hakkında önemli not: kilit nesnesi olarak ne kullandığınıza dikkat edin!
Yukarıdaki user2277816 kod parçacığı, bir dizgi hazır bilgisine başvurunun kilitleme nesnesi olarak kullanılması bakımından bu noktayı göstermektedir. Dize değişmezlerinin Java'da otomatik olarak yerleştirildiğini ve sorunu görmeye başlamanız gerektiğini unutmayın: Değişmez "kilit" üzerinde eşitlenen her kod parçası aynı kilidi paylaşır! Bu, tamamen ilgisiz kod parçalarıyla kolayca kilitlenmelere yol açabilir.
Dikkat etmeniz gereken sadece String nesneleri değildir. Kutulu temel öğeler de bir tehlikedir, çünkü otomatik boks ve valueOf yöntemleri, değere bağlı olarak aynı nesneleri yeniden kullanabilir.
Daha fazla bilgi için bkz. Https://www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused
Genellikle yöntem düzeyinde bir kilit kullanmak çok kaba olur. Neden tüm yöntemi kilitleyerek paylaşılan kaynaklara erişmeyen bir kod parçasını kilitlemelisiniz. Her nesnenin bir kilidi olduğundan, blok düzeyinde senkronizasyonu uygulamak için sahte nesneler oluşturabilirsiniz. Tüm yöntemi kilitlemediği için blok seviyesi daha verimlidir.
İşte bazı örnek
Yöntem Düzeyi
class MethodLevel {
//shared among threads
SharedResource x, y ;
public void synchronized method1() {
//multiple threads can't access
}
public void synchronized method2() {
//multiple threads can't access
}
public void method3() {
//not synchronized
//multiple threads can access
}
}
Blok Seviyesi
class BlockLevel {
//shared among threads
SharedResource x, y ;
//dummy objects for locking
Object xLock = new Object();
Object yLock = new Object();
public void method1() {
synchronized(xLock){
//access x here. thread safe
}
//do something here but don't use SharedResource x, y
// because will not be thread-safe
synchronized(xLock) {
synchronized(yLock) {
//access x,y here. thread safe
}
}
//do something here but don't use SharedResource x, y
//because will not be thread-safe
}//end of method1
}
[Düzenle]
For Collection
gibi Vector
ve Hashtable
onlar senkronize zaman vardır ArrayList
ya HashMap
olmayan ve anahtar kelime senkronize veya Koleksiyonları eşitlenmiş yöntemin çağırmak seti gerek:
Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map
List myList = Collections.synchronizedList (myList); // single lock for the entire list
Tek fark: senkronize bloklar, senkronize yöntemden farklı olarak granüler kilitlemeye izin verir
Temel olarak synchronized
blok veya yöntemler, bellek tutarsızlık hatalarından kaçınarak iş parçacığı güvenli kodu yazmak için kullanılmıştır.
Bu soru çok eski ve son 7 yılda çok şey değişti. İplik güvenliği için yeni programlama yapıları tanıtıldı.
synchronied
Bloklar yerine gelişmiş eşzamanlılık API'sini kullanarak iş parçacığı güvenliğini sağlayabilirsiniz . Bu belge sayfası , iplik güvenliğini sağlamak için iyi programlama yapıları sağlar.
Nesneleri Kilitle , birçok eşzamanlı uygulamayı basitleştiren kilitleme deyimlerini destekler.
Yürütücüler iş parçacıklarını başlatmak ve yönetmek için üst düzey bir API tanımlar. Java.util.concurrent tarafından sağlanan yönetici uygulamaları, büyük ölçekli uygulamalar için uygun iş parçacığı havuzu yönetimi sağlar.
Eşzamanlı Koleksiyonlar büyük veri koleksiyonlarını yönetmeyi kolaylaştırır ve senkronizasyon ihtiyacını büyük ölçüde azaltabilir.
Atomik Değişkenler , senkronizasyonu en aza indiren ve bellek tutarlılığı hatalarını önlemeye yardımcı olan özelliklere sahiptir.
ThreadLocalRandom (JDK 7'de), birden fazla iş parçacığından verimli psödondom sayılarının üretilmesini sağlar.
Senkronize için daha iyi değiştirme , API kullanan ReentrantLock'turLock
Eşzamanlı karşılıklı dışlama Kilidi, eşzamanlı yöntemler ve deyimler kullanılarak erişilen örtülü monitör kilidiyle aynı temel davranış ve semantiğe sahip, ancak genişletilmiş yeteneklere sahip.
Kilitli örnek:
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
Diğer programlama yapıları için de java.util.concurrent ve java.util.concurrent.atomic paketlerine bakın .
Bu ilgili soruya da bakın:
Genelde bunlar çoğunlukla, nesnenin üstü kapalı olarak kullanılan nesnenin monitörü hakkında açık olmaktan farklıdır. Bazen göz ardı olduğunu düşünüyorum senkronize yöntemlerin bir dezavantajı size senkronize etmek için "bu" referans kullanarak aynı nesnede kilitleme dış nesnelerin kilitleme olasılığını açık bırakıyor olmasıdır. Eğer içine girerseniz bu çok ince bir hata olabilir. Dahili açık bir Nesne veya varolan başka bir alanda eşitleme yapmak, eşitlemeyi tamamen içine alan bu sorunu önleyebilir.
Daha önce de belirtildiği gibi, senkronize fonksiyon sadece "this" kullandığında senkronize blok kilit nesnesi olarak kullanıcı tanımlı değişkeni kullanabilir. Ve elbette, işlevinizin senkronize edilmesi gereken alanlarla manipüle edebilirsiniz. Ancak herkes kilit nesnesi olarak "this" kullanarak senkronize fonksiyon ve blok arasında hiçbir fark olmadığını söylüyor. Bu doğru değil, her iki durumda da oluşturulacak bayt kodunda fark var. Senkronize blok kullanımı durumunda, "bu" ya referans veren yerel değişken tahsis edilmelidir. Ve sonuç olarak işlev için biraz daha büyük bir boyuta sahip olacağız (sadece birkaç sayıda fonksiyonunuz varsa ilgili değil).
Burada bulabileceğiniz farkın daha ayrıntılı açıklaması: http://www.artima.com/insidejvm/ed2/threadsynchP.html
Senkronize yöntemler durumunda, bir Nesne üzerinde kilit alınacaktır. Ancak senkronize blokla giderseniz kilidin alınacağı bir nesneyi belirleme seçeneğiniz vardır.
Misal :
Class Example {
String test = "abc";
// lock will be acquired on String test object.
synchronized (test) {
// do something
}
lock will be acquired on Example Object
public synchronized void testMethod() {
// do some thing
}
}
Bunun eski bir soru olduğunu biliyorum, ama buradaki yanıtları hızlı bir şekilde okuduğumda, kimsenin zaman zaman bir synchronized
yöntemin yanlış kilit olabileceğinden bahsetmediğini gerçekten görmedim .
Uygulamada Java Eşzamanlılığı'ndan (s. 72):
public class ListHelper<E> {
public List<E> list = Collections.syncrhonizedList(new ArrayList<>());
...
public syncrhonized boolean putIfAbsent(E x) {
boolean absent = !list.contains(x);
if(absent) {
list.add(x);
}
return absent;
}
Yukarıdaki kod, iş parçacığı açısından güvenli görünmektedir . Ancak, gerçekte değil. Bu durumda, kilit sınıf örneğinde elde edilir. Ancak, listenin bu yöntemi kullanmayan başka bir iş parçacığı tarafından değiştirilmesi mümkündür . Doğru yaklaşım,
public boolean putIfAbsent(E x) {
synchronized(list) {
boolean absent = !list.contains(x);
if(absent) {
list.add(x);
}
return absent;
}
}
Yukarıdaki kod , senkronize blok tamamlanıncaya kadar listeyi değiştirmeye çalışan tüm evrelerin listeyi değiştirmesini engeller.
List
senkronize edilmesi gerekmeyen bir kod günlüğü varsa , sadece yöntemi yerine tüm yöntemi kilitlemek performans sorunlarına yol açabilir
Pratik bir mesele olarak, senkronize yöntemlerin senkronize bloklara göre avantajı, daha salak dirençli olmalarıdır; kilitlemek için rasgele bir nesne seçemediğiniz için, senkronize yöntem sözdizimini yanlış bir dize değişmezine sabitlemek veya iş parçacıklarının altından değiştirilen değişken bir alanın içeriğini kilitlemek gibi aptalca şeyler yapmak için kötüye kullanamazsınız.
Öte yandan, senkronize yöntemlerle, kilidi nesneye referans alabilen herhangi bir iş parçacığı tarafından alınmasını önleyemezsiniz.
Bu nedenle, yöntemlerde bir değiştirici olarak senkronize edilmiş kullanmak, inek orkilerinizi kendilerini incitmekten korumakta daha iyidir, senkronize blokları özel son kilit nesneleriyle birlikte kullanmak, kendi kodunuzu inek orkörlerinden korumakta daha iyidir.
Java teknik özellikleri özetinden: http://www.cs.cornell.edu/andru/javaspec/17.doc.html
Senkronize ifade (§14.17) bir nesneye referans hesaplar; daha sonra bu nesne üzerinde bir kilit eylemi gerçekleştirmeye çalışır ve kilit eylemi başarıyla tamamlanana kadar daha fazla ilerlemez. ...
Senkronize bir yöntem (§8.4.3.5) çağrıldığında otomatik olarak bir kilit eylemi gerçekleştirir; kilit eylemi başarıyla tamamlanana kadar gövdesi yürütülmez. Yöntem bir örnek yöntemiyse , çağrıldığı örnekle ilişkili olan kilidi kilitler (yani, yöntemin gövdesinin yürütülmesi sırasında bu şekilde bilinecek nesne). Yöntem statikse , yöntemin tanımlandığı sınıfı temsil eden Class nesnesiyle ilişkili kilidi kilitler. ...
Bu açıklamalara dayanarak, önceki yanıtların çoğunun doğru olduğunu söyleyebilirim ve senkronize edilmiş bir yöntem, aksi takdirde yöntemin olduğu sınıfı temsil eden sınıf nesnesini nasıl alacağınızı anlamanız gereken statik yöntemler için özellikle yararlı olabilir. tanımladı."
Düzenleme: Aslında bu gerçek Java spec tırnak olduğunu düşündüm. Bu sayfanın spesifikasyonun sadece bir özeti / açıklaması olduğu açıklığa kavuşturuldu
TLDR; Ne synchronized
değiştiriciyi ne de synchronized(this){...}
ifadeyi kullanın, ancak özel bir nesneyi tutan bir son örnek alanı synchronized(myLock){...}
nerede myLock
.
synchronized
Yöntem bildiriminde değiştiriciyi kullanma synchronized(..){ }
ile yöntem gövdesindeki ifade arasındaki fark şudur :
synchronized
Yöntemin imzasının belirtilen değiştirici
synchronized(this) { .... }
vethis
statik olmayan yöntemi veya statik bir yöntem ile ilgili bildirilen parça sınıf ilan ettiği kilidi olarak nesne.synchronized(...){...}
İfadesi olanak sağlar
Bununla birlikte, kullanılarak synchronized
değiştirici ya da synchronized(...) {...}
birlikte this
(olduğu gibi kilit nesne olarak synchronized(this) {...}
) aynı dezavantajlara sahiptir. Her ikisi de senkronize etmek için kendi örneğini kilit nesnesi olarak kullanır. Bu tehlikelidir, çünkü yalnızca nesnenin kendisi değil , aynı zamanda bu nesneye başvuruda bulunan diğer herhangi bir harici nesne / kod da nesneyi potansiyel olarak ciddi yan etkilere (performans bozulması ve kilitlenmeler ) sahip bir senkronizasyon kilidi olarak kullanabilir .
Bu nedenle en iyi uygulama, synchronized
değiştiriciyi veya synchronized(...)
ifadeyi this
kilit nesnesi olarak değil, bu nesneye özel bir kilit nesnesini kullanmaktır. Örneğin:
public class MyService {
private final lock = new Object();
public void doThis() {
synchronized(lock) {
// do code that requires synchronous execution
}
}
public void doThat() {
synchronized(lock) {
// do code that requires synchronous execution
}
}
}
Birden fazla kilit nesnesi de kullanabilirsiniz, ancak iç içe kullanıldığında bunun kilitlenmeyle sonuçlanmadığından emin olmak için özel dikkat gösterilmelidir.
public class MyService {
private final lock1 = new Object();
private final lock2 = new Object();
public void doThis() {
synchronized(lock1) {
synchronized(lock2) {
// code here is guaranteed not to be executes at the same time
// as the synchronized code in doThat() and doMore().
}
}
public void doThat() {
synchronized(lock1) {
// code here is guaranteed not to be executes at the same time
// as the synchronized code in doThis().
// doMore() may execute concurrently
}
}
public void doMore() {
synchronized(lock2) {
// code here is guaranteed not to be executes at the same time
// as the synchronized code in doThis().
// doThat() may execute concurrently
}
}
}
Sanırım bu soru Thread Safe Singleton ve Double check lock ile tembel başlatma arasındaki fark hakkında . Belirli bir singleton uygulamak gerektiğinde her zaman bu makaleye başvuruyorum.
Peki, bu bir Thread Safe Singleton :
// Java program to create Thread Safe
// Singleton class
public class GFG
{
// private instance, so that it can be
// accessed by only by getInstance() method
private static GFG instance;
private GFG()
{
// private constructor
}
//synchronized method to control simultaneous access
synchronized public static GFG getInstance()
{
if (instance == null)
{
// if instance is null, initialize
instance = new GFG();
}
return instance;
}
}
Artıları:
Tembel başlatma mümkündür.
İplik korumalıdır.
Eksileri:
- getInstance () yöntemi senkronize edilir, böylece birden çok iş parçacığı aynı anda erişemediğinden yavaş performansa neden olur.
Bu, Çift çek kilitlemeli Tembel başlatmadır :
// Java code to explain double check locking
public class GFG
{
// private instance, so that it can be
// accessed by only by getInstance() method
private static GFG instance;
private GFG()
{
// private constructor
}
public static GFG getInstance()
{
if (instance == null)
{
//synchronized block to remove overhead
synchronized (GFG.class)
{
if(instance==null)
{
// if instance is null, initialize
instance = new GFG();
}
}
}
return instance;
}
}
Artıları:
Tembel başlatma mümkündür.
Aynı zamanda iplik korumalıdır.
Senkronize edilen anahtar kelime nedeniyle performans düştü.
Eksileri:
İlk kez performansı etkileyebilir.
Eksileri olarak. çift kontrol kilitleme yöntemi katlanabilir, bu nedenle yüksek performanslı çok iş parçacıklı uygulamalar için kullanılabilir.
Daha fazla ayrıntı için lütfen bu makaleye bakın:
https://www.geeksforgeeks.org/java-singleton-design-pattern-practices-examples/
Konu ile senkronizasyon. 1) ASLA çalışmadığı bir iş parçacığında senkronize (bu) kullanmayın. (This) ile senkronize etmek, geçerli iş parçacığını kilitleme iş parçacığı nesnesi olarak kullanır. Her bir iş parçacığı diğer iş parçacıklarından bağımsız olduğundan senkronizasyon koordinasyonu YOKTUR. 2) Kod testleri, Mac'te Java 1.6'da yöntem eşitlemesinin çalışmadığını gösterir. 3) senkronize (lockObj) burada lockObj, üzerinde senkronize edilen tüm iş parçacıklarının ortak bir paylaşılan nesnesidir. 4) ReenterantLock.lock () ve .unlock () çalışır. Bunun için Java eğiticilerine bakın.
Aşağıdaki kod bu noktaları gösterir. Ayrıca, bir Vector öğesine eklenen birçok iş parçacığının herhangi bir bilgi kaybetmediğini, ArrayList ile aynı bilgilerin kaybedebileceğini göstermek için ArrayList ile değiştirilecek iş parçacığı güvenli Vector içerir. 0) Geçerli kod, yarış koşulları nedeniyle bilgi kaybını gösterir A) Geçerli A etiketli akımı yorumlayın ve üstündeki A çizgisini kaldırın, ardından çalıştırın, yöntem veri kaybeder, ancak olmamalıdır. B) A, ters B ve // bitiş bloğu} adımlarını ters çevirin. Sonra sonuçları görmek için çalıştırın veri kaybı yok C) Yorum B, uncomment C Çalıştır, bkz. Tüm varyasyonları tamamlamak için zamanınız yok, umarım bu yardımcı olur. Senkronizasyon açıksa (bu) veya yöntem senkronizasyonu çalışıyorsa, lütfen test ettiğiniz Java ve OS sürümünü belirtin. Teşekkür ederim.
import java.util.*;
/** RaceCondition - Shows that when multiple threads compete for resources
thread one may grab the resource expecting to update a particular
area but is removed from the CPU before finishing. Thread one still
points to that resource. Then thread two grabs that resource and
completes the update. Then thread one gets to complete the update,
which over writes thread two's work.
DEMO: 1) Run as is - see missing counts from race condition, Run severa times, values change
2) Uncomment "synchronized(countLock){ }" - see counts work
Synchronized creates a lock on that block of code, no other threads can
execute code within a block that another thread has a lock.
3) Comment ArrayList, unComment Vector - See no loss in collection
Vectors work like ArrayList, but Vectors are "Thread Safe"
May use this code as long as attribution to the author remains intact.
/mf
*/
public class RaceCondition {
private ArrayList<Integer> raceList = new ArrayList<Integer>(); // simple add(#)
// private Vector<Integer> raceList = new Vector<Integer>(); // simple add(#)
private String countLock="lock"; // Object use for locking the raceCount
private int raceCount = 0; // simple add 1 to this counter
private int MAX = 10000; // Do this 10,000 times
private int NUM_THREADS = 100; // Create 100 threads
public static void main(String [] args) {
new RaceCondition();
}
public RaceCondition() {
ArrayList<Thread> arT = new ArrayList<Thread>();
// Create thread objects, add them to an array list
for( int i=0; i<NUM_THREADS; i++){
Thread rt = new RaceThread( ); // i );
arT.add( rt );
}
// Start all object at once.
for( Thread rt : arT ){
rt.start();
}
// Wait for all threads to finish before we can print totals created by threads
for( int i=0; i<NUM_THREADS; i++){
try { arT.get(i).join(); }
catch( InterruptedException ie ) { System.out.println("Interrupted thread "+i); }
}
// All threads finished, print the summary information.
// (Try to print this informaiton without the join loop above)
System.out.printf("\nRace condition, should have %,d. Really have %,d in array, and count of %,d.\n",
MAX*NUM_THREADS, raceList.size(), raceCount );
System.out.printf("Array lost %,d. Count lost %,d\n",
MAX*NUM_THREADS-raceList.size(), MAX*NUM_THREADS-raceCount );
} // end RaceCondition constructor
class RaceThread extends Thread {
public void run() {
for ( int i=0; i<MAX; i++){
try {
update( i );
} // These catches show when one thread steps on another's values
catch( ArrayIndexOutOfBoundsException ai ){ System.out.print("A"); }
catch( OutOfMemoryError oome ) { System.out.print("O"); }
}
}
// so we don't lose counts, need to synchronize on some object, not primitive
// Created "countLock" to show how this can work.
// Comment out the synchronized and ending {, see that we lose counts.
// public synchronized void update(int i){ // use A
public void update(int i){ // remove this when adding A
// synchronized(countLock){ // or B
// synchronized(this){ // or C
raceCount = raceCount + 1;
raceList.add( i ); // use Vector
// } // end block for B or C
} // end update
} // end RaceThread inner class
} // end RaceCondition outter class