Senkronize edilmiş (nedense) bir kişi neden ReentrantLock kullanmalı?


317

Eğer eşzamanlı olarak kilit bir kullanmak eğer önemli kılan anlamaya çalışıyorum synchronized (this). Aşağıdaki kukla kodda, ben de yapabilirim:

  1. tüm yöntemi senkronize etti veya savunmasız alanı senkronize et ( synchronized(this){...})
  2. VEYA Güvenlik açığından etkilenen kod alanını bir ReentrantLock ile kilitleyin.

Kod:

    private final ReentrantLock lock = new ReentrantLock(); 
    private static List<Integer> ints;

    public Integer getResult(String name) { 
        .
        .
        .
        lock.lock();
        try {
            if (ints.size()==3) {
                ints=null;
                return -9;
            }   

            for (int x=0; x<ints.size(); x++) {
                System.out.println("["+name+"] "+x+"/"+ints.size()+". values >>>>"+ints.get(x));
            }

        } finally {
            lock.unlock();
        } 
        return random;
}

1
BTW tüm java iç kilitleri doğası gereği yeniden evlenmiştir.
Aniket Thakur

@pongapundit böylece synchronized(this){synchronized(this){//some code}}ölü kilide neden olmaz. Bir kaynak üzerinde monitör alırlarsa ve tekrar istiyorlarsa kendiliğinden kilitlemek için ölü kilit olmadan alabilirler.
Aniket Thakur

Yanıtlar:


474

Bir ReentrantLock olduğunu yapılandırılmamış aksine synchronizedyapılara - yani kilitlemek için bir blok yapısını kullanmaya gerek yoktur ve hatta yöntemlerle genelinde bir kilit tutabilir. Bir örnek:

private ReentrantLock lock;

public void foo() {
  ...
  lock.lock();
  ...
}

public void bar() {
  ...
  lock.unlock();
  ...
}

Bu tür bir akışın bir synchronizedyapıdaki tek bir monitör vasıtasıyla temsil edilmesi imkansızdır .


Bunun yanı sıra, kilit yoklamayıReentrantLock destekler ve zaman aşımını destekleyen kesilebilir kilit bekler . ayrıca, daha esnek iş parçacığı zamanlamasına olanak tanıyan yapılandırılabilir adalet politikası desteği vardır .ReentrantLock

Bu sınıfın yapıcısı isteğe bağlı bir adalet parametresini kabul eder . Ayarlandığında true, çekişme altında, kilitler en uzun bekleyen iş parçacığına erişim izni verir. Aksi takdirde, bu kilit herhangi bir erişim sırasını garanti etmez. Birçok iş parçacığı tarafından erişilen adil kilitleri kullanan programlar, varsayılan ayarı kullananlara göre daha düşük genel verim gösterebilir (yani, daha yavaş; genellikle çok daha yavaş), ancak kilit elde etmek ve açlık eksikliğini garanti etmek için zaman zaman daha küçük varyanslara sahip olabilir. Bununla birlikte, kilitlerin adilliğinin iplik programlamanın adilliğini garanti etmediğini unutmayın. Bu nedenle, adil bir kilit kullanan birçok dişten biri, diğer aktif dişler ilerlemez ve şu anda kilidi tutmuyorken, arka arkaya birçok kez elde edebilir. Ayrıca,tryLockyöntemi adalet ayarına uymaz. Diğer iş parçacıkları bekliyor olsa bile kilidin kullanılabilir olması başarılı olacaktır.


ReentrantLock ayrıca daha ölçeklenebilir olabilir ve daha yüksek çekişme altında daha iyi performans gösterebilir . Bununla ilgili daha fazla bilgiyi buradan edinebilirsiniz .

Ancak bu iddiaya itiraz edilmiştir; aşağıdaki yoruma bakın:

Evresel kilit testinde her seferinde yeni bir kilit oluşturulur, bu nedenle özel bir kilitleme yoktur ve elde edilen veriler geçersizdir. Ayrıca, IBM bağlantısı, temel ölçüt için hiçbir kaynak kodu sunmadığından, testin doğru bir şekilde yapılıp yapılmadığını belirlemek imkansızdır.


Ne zaman ReentrantLocks kullanmalısınız ? Bu developerWorks makalesine göre ...

Cevap oldukça basit - synchronizedzamanlanmış kilit beklemeleri, kesilebilir kilit beklemeleri, blok yapısız kilitler, çoklu koşul değişkenleri veya kilit yoklaması gibi sağlamadığı bir şeye ihtiyacınız olduğunda kullanın . ReentrantLockölçeklenebilirlik avantajları da vardır ve gerçekten yüksek çekişme gösteren bir durumunuz varsa kullanmalısınız, ancak synchronizedblokların büyük çoğunluğunun yüksek çekişme olsa bile neredeyse hiç çekişme göstermediğini unutmayın . Senkronizasyonun yetersiz olduğu kanıtlanana kadar senkronizasyon ile geliştirmeyi tavsiye edersiniz, yalnızca "performans daha iyi olacaktır"ReentrantLock. Unutmayın, bunlar ileri düzey kullanıcılar için gelişmiş araçlardır. (Ve gerçekten ileri düzey kullanıcılar, basit araçların yetersiz olduğuna ikna olana kadar bulabilecekleri en basit araçları tercih etme eğilimindedir.) Her zaman olduğu gibi, önce doğru yapın ve daha sonra daha hızlı yapmanız gerekip gerekmediği konusunda endişe edin.


26
Lycog.com'a 'daha ölçeklenebilir olduğu bilinen' bağlantı kaldırılmalıdır. Evresel kilit testinde her seferinde yeni bir kilit oluşturulur, bu nedenle özel bir kilitleme yoktur ve elde edilen veriler geçersizdir. Ayrıca, IBM bağlantısı, temel ölçüt için hiçbir kaynak kodu sunmadığından, testin doğru bir şekilde gerçekleştirilip gerçekleştirilmediğini tanımlamak imkansızdır. Şahsen, tüm iddia esasen desteklenmediğinden, ölçeklenebilirlik hakkındaki tüm çizgiyi kaldırırım.
Dev

2
Cevabınız ışığında gönderiyi değiştirdim.
oldrinb

6
Performans sizin için büyük bir endişe kaynağıysa, Senkronizasyona hiç ihtiyacınız olmayan bir yol aramayı unutmayın.
mcoolive

2
Performans olayı benim için hiç mantıklı değil. Eğer reantrant kilidi daha iyi performans gösterseydi, neden senkronize olmuyordu, sadece bir reantrant kilidi de aynı şekilde uygulanmıyor?
tObi

2
@ user2761895 ReentrantLockPseudoRandomLycog bağlantısındaki kod her çağrışımı yepyeni, sınırsız kilitler kullanıyor setSeedvenext
oldrinb

14

ReentrantReadWriteLocközel synchronized(this)amaçlı bir kilit iken genel amaçlı bir kilittir. Benzerler ama aynı değiller.

Bunun synchronized(this)yerine kullanabileceğiniz konusunda haklısınız , ReentrantReadWriteLockancak tam tersi her zaman doğru değildir.

Neyin ReentrantReadWriteLocközel olduğunu daha iyi anlamak isterseniz, üretici-tüketici iş parçacığı senkronizasyonu hakkında bazı bilgilere bakın.

Genel olarak, tüm yöntem senkronizasyonu ve genel amaçlı senkronizasyonun ( synchronizedanahtar sözcüğü kullanarak ) senkronizasyonun anlambilimi hakkında çok fazla düşünmeden çoğu uygulamada kullanılabileceğini hatırlayabilirsiniz, ancak performansı kodunuzdan sıkmanız gerekiyorsa daha ince taneli veya özel amaçlı senkronizasyon mekanizmalarını araştırın.

Bu arada, synchronized(this)- ve genel olarak bir sınıf örneği kullanarak kilitleme, sorunlu olabilir, çünkü kodunuzu potansiyel ölü kilitlere açar çünkü bilerek başka biri programınızda başka bir yere nesnenize karşı kilitlemeye çalışabilir.


potansiyel ölü kilitleri önlemek için bilerek başka biri nesneye karşı progame başka bir yerde kilitleme çalışabilirsiniz senkronizasyon Monitörü olarak özel bir nesne örneği kullanın: public class MyLock { private final Object protectedLongLockingMonitor = new Object(); private long protectedLong = 0L; public void incrementProtectedLong() { synchronized(protectedLongLockingMonitor) { protectedLong++; } } }
sushicutta

9

ReentrantLock ile ilgili oracle dokümantasyon sayfasından :

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.

  1. Bir ReentrantLock , en son başarıyla kilitlenen iş parçacığına aittir, ancak henüz kilidini açmaz . Kilit başka bir iş parçacığına ait olmadığında, kilidi çağıran bir iş parçacığı kilit döndürür. Geçerli iş parçacığı zaten kilide sahipse yöntem hemen dönecektir.

  2. Bu sınıfın yapıcısı isteğe bağlı bir adalet parametresini kabul eder . Doğru olarak ayarlandığında, çekişme altında kilitler, en uzun süre bekleyen iş parçacığına erişim izni verir . Aksi takdirde, bu kilit herhangi bir erişim sırasını garanti etmez.

Bu makaleye göre ReentrantLock temel özellikleri

  1. Kesintisiz kilitleme yeteneği.
  2. Kilit beklerken zaman aşımı yeteneği.
  3. Adil kilit oluşturma gücü.
  4. Kilit için bekleyen iş parçacığı listesini almak için API.
  5. Engellemeden kilit denemek için esneklik.

Okuma ve yazma işlemlerinde ayrıntılı kilitleme üzerinde daha fazla denetim sahibi olmak için ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock'u kullanabilirsiniz .

Farklı türdeki ReentrantLocks kullanımı hakkında Benjamen tarafından yazılmış bu makaleye bir göz atın


2

İş parçacığı açlığını önlemek için reentrant kilitlerini bir adalet politikası veya zaman aşımı ile kullanabilirsiniz. Bir iş parçacığı adalet politikası uygulayabilirsiniz. kaynaklarınıza ulaşmak için sonsuza kadar bekleyen bir iş parçacığından kaçınmanıza yardımcı olacaktır.

private final ReentrantLock lock = new ReentrantLock(true);
//the param true turns on the fairness policy. 

"Adalet politikası" yürütülecek bir sonraki çalıştırılabilir iş parçacığını seçer. Önceliğe, son koşundan bu yana geçen zamana, falan filan

ayrıca, senkronize bloktan kaçamazsa süresiz olarak engelleyebilir. Reentrantlock zaman aşımı ayarlanmış olabilir.


1

Senkronize kilitler , bir iş parçacığının yürütülmesinden sonra paralel olarak çalışan herhangi bir iş parçacığının kilidi elde edebileceği herhangi bir bekleme kuyruğu mekanizması sunmaz. Sistemde bulunan ve daha uzun süre çalışan ipliğin, paylaşılan kaynağa asla erişme şansı olmaması, böylece açlığa neden olur.

Evirici kilitler çok esnektir ve bir iş parçacığı daha uzun bir süre bekliyorsa ve şu anda yürütülen iş parçacığının tamamlanmasından sonra, daha uzun bekleyen iş parçasının paylaşılan kaynağa erişim şansını azaltabildiğinden emin olabiliriz. sistemin verimi ve daha fazla zaman alıcı hale getirilmesi.


1

Bu kodun bir iş parçacığında çalıştığını varsayalım:

private static ReentrantLock lock = new ReentrantLock();

void accessResource() {
    lock.lock();
    if( checkSomeCondition() ) {
        accessResource();
    }
    lock.unlock();
}

İş parçacığı kilide sahip olduğundan, birden çok çağrının lock () işlevine izin verir, böylece kilidi yeniden girer. Bu bir referans sayısı ile elde edilebilir, böylece tekrar kilit almak zorunda kalmazsınız.


0

Akılda tutulması gereken bir şey:

' ReentrantLock ' adı, yeniden girmedikleri diğer kilitleme mekanizmaları hakkında yanlış bir mesaj veriyor. Bu doğru değil. 'Senkronize' ile alınan kilit de Java'da yeniden girilir.

Temel fark, 'senkronize' özelliğinin (her Nesnenin sahip olduğu) kilit API kullanmasıdır.


0

Ben wait / notify / notifyTüm yöntemler nadiren kullanılan yöntemlerle tüm nesneleri kirlettiği için Object sınıfına ait değildir. Özel bir Lock sınıfında çok daha anlamlı. Bu açıdan, belki de eldeki iş için açıkça tasarlanmış bir araç kullanmak daha iyidir - yani ReentrantLock.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.