Programım için Java'da çoklu iş parçacığı kullanıyorum. Ben başarıyla iş parçacığı çalıştırmak var ama ben kullanırken Thread.wait()
, atıyor java.lang.IllegalMonitorStateException
. Bildirilene kadar bir konuyu nasıl bekletebilirim?
Programım için Java'da çoklu iş parçacığı kullanıyorum. Ben başarıyla iş parçacığı çalıştırmak var ama ben kullanırken Thread.wait()
, atıyor java.lang.IllegalMonitorStateException
. Bildirilene kadar bir konuyu nasıl bekletebilirim?
Yanıtlar:
Çalışabilmek synchronized
için bir blokta olmanız gerekir Object.wait()
.
Ayrıca, eski okul iş parçacığı paketleri yerine eşzamanlılık paketlerine bakmanızı öneririm. Daha güvenli ve birlikte çalışmak çok daha kolay .
Mutlu kodlama.
DÜZENLE
Object.wait()
İstisna nesneler kilidini tutmadan erişim kazanmaya çalıştığınızda ne olduğu anlamına geldiğini varsaydım .
wait
içinde tanımlanmış Object
, değil Thread
. Monitör açık Thread
bir şekilde tahmin edilemez.
Tüm Java nesnelerinin monitörleri olmasına rağmen, genellikle özel bir kilide sahip olmak daha iyidir:
private final Object lock = new Object();
Tanımlı bir sınıfı kullanarak, küçük bellek maliyetiyle (işlem başına yaklaşık 2K) tanılamayı okumak biraz daha kolay olabilir:
private static final class Lock { }
private final Object lock = new Lock();
Amacıyla wait
veya notify
/ notifyAll
bir nesne, sizinle kilit tutan gerekmektedir synchronized
açıklamada. Ayrıca, while
uyandırma durumunu kontrol etmek için bir döngüye ihtiyacınız olacaktır (nedenini açıklamak için iplik üzerinde iyi bir metin bulun).
synchronized (lock) {
while (!isWakeupNeeded()) {
lock.wait();
}
}
Bildirmek için:
synchronized (lock) {
makeWakeupNeeded();
lock.notifyAll();
}
Birden çok iş parçacığına girerken hem Java dilini hem de java.util.concurrent.locks
kilitlerini (ve java.util.concurrent.atomic
) anlamaya değer . Ancak, java.util.concurrent
mümkün olduğunda veri yapılarını kullanın .
wait
, evet asla ulaşamazsınız notify
. Bununla birlikte, Object.wait
"İş parçacığı bu monitörün sahipliğini serbest bırakır" API belgelerinde . Bu yüzden wait
kapalı synchronized
blokların dışındayken (aynı nesne için, aynı nesne synchronized
üzerinde birden fazla blok olabilir ).
Ben bu konu neredeyse 2 yaşında olduğunu biliyorum ama aynı sorunu ile bu Q / A oturumuna geldi beri hala bunu kapatmak gerekir ...
Lütfen illegalMonitorException'ın bu tanımını tekrar tekrar okuyun ...
IllegalMonitorException, bir iş parçacığının bir nesnenin monitöründe beklemeye çalıştığını veya bir nesnenin izleyicisini bekleyen diğer iş parçacıklarını belirtilen monitöre sahip olmadan bildirmeye çalıştığını belirtir.
Bu satır tekrar tekrar diyor, 2 durumdan biri meydana geldiğinde IllegalMonitorException geliyor ....
1> belirtilen monitöre sahip olmadan bir nesnenin monitöründe bekleyin.
2> belirtilen monitöre sahip olmadan bir nesnenin ekranında bekleyen diğer iş parçacıklarını bilgilendirin.
Bazılarının cevapları olabilir ... hepsi yok, lütfen 2 ifadeyi kontrol edin ....
senkronize (nesne)
object.wait ()
Her iki nesne de aynı ise ... illegalMonitorException gelemez.
Şimdi tekrar IllegalMonitorException tanımını okuyun ve tekrar unutmayacaksınız ...
Yorumlarınıza dayanarak böyle bir şey yapıyormuşsunuz gibi geliyor:
Thread thread = new Thread(new Runnable(){
public void run() { // do stuff }});
thread.start();
...
thread.wait();
Üç sorun var.
Diğerlerinin söylediği gibi obj.wait()
, sadece mevcut iş parçacığı için ilkel kilit / muteks tutarsa çağrılabilir obj
. Geçerli iş parçacığı kilidi tutmazsa, gördüğünüz özel durumu alırsınız.
thread.wait()
İfadesi gerek yapmak bekliyor gibi görünüyor ne yapmaz. Özellikle, atanan iş parçacığının beklemesine neden thread.wait()
olmaz . Bunun yerine , geçerli evre başka bir evre çağrılıncaya kadar bekler thread.notify()
veyathread.notifyAll()
.
Aslında bir Thread
örneği istemiyorsa duraklamaya zorlamanın güvenli bir yolu yoktur . (Java'nın buna en yakın olanı kullanımdan kaldırılmış Thread.suspend()
yöntemdir, ancak Javadoc'ta açıklandığı gibi bu yöntem doğal olarak güvenli değildir.)
Yeni başlamayı Thread
duraklatmak istiyorsanız, bunu yapmanın en iyi yolu, bir CountdownLatch
örnek oluşturmak ve await()
kendini duraklatmak için mandalda iş parçacığı araması yapmaktır . Ana iş parçacığı countDown()
, duraklatılmış iş parçacığının devam etmesi için mandalı çağırır .
Önceki noktalara dik olarak, bir Thread
nesneyi kilit / muteks olarak kullanmak sorunlara neden olabilir. Örneğin, javadoc Thread::join
şöyle diyor:
Bu uygulama,
this.wait
koşullandırılmış bir çağrı döngüsü kullanırthis.isAlive
. Bir iş parçacığı sona erdiğindethis.notifyAll
yöntem çağrılır. Uygulamalar kullanmayın önerilirwait
,notify
yanotifyAll
üzerindeThread
durumlarda.
Kod göndermediğiniz için karanlıkta çalışıyoruz. İstisnanın detayları nelerdir?
Thread.wait () öğesini konu içinden mi yoksa dışından mı çağırıyorsunuz?
IllegalMonitorStateException için javadoc göre, bu soruyorum:
Bir iş parçacığının, bir nesnenin monitöründe beklemeye çalıştığını veya belirtilen monitöre sahip olmadan bir nesnenin ekranında bekleyen diğer iş parçacıklarını bilgilendirmeye çalıştığını göstermek için atılır.
Bu cevabı açıklığa kavuşturmak için, bir iş parçacığını beklemeye yönelik bu çağrı, senkronize edilmiş bir bloktan çağrılmasına rağmen IllegalMonitorStateException'ı da atar:
private static final class Lock { }
private final Object lock = new Lock();
@Test
public void testRun() {
ThreadWorker worker = new ThreadWorker();
System.out.println ("Starting worker");
worker.start();
System.out.println ("Worker started - telling it to wait");
try {
synchronized (lock) {
worker.wait();
}
} catch (InterruptedException e1) {
String msg = "InterruptedException: [" + e1.getLocalizedMessage() + "]";
System.out.println (msg);
e1.printStackTrace();
System.out.flush();
}
System.out.println ("Worker done waiting, we're now waiting for it by joining");
try {
worker.join();
} catch (InterruptedException ex) { }
}
wait()
.
worker.wait()
? O zaman kilit üzerinde değil, işçi üzerinde senkronize olmalısınız.
IllegalMonitorStateException ile başa çıkmak için, bekleme, bildirme ve bildirme işlemlerinin tüm çağrılarının yalnızca çağıran evre uygun monitöre sahip olduğunda gerçekleştiğini doğrulamalısınız. . En basit çözüm, bu çağrıları senkronize bloklara dahil etmektir. Senkronize ifadede çağrılacak olan senkronizasyon nesnesi, monitörü edinilmesi gereken nesnedir.
Monitör kavramını anlamak için basit bir örnek
public class SimpleMonitorState {
public static void main(String args[]) throws InterruptedException {
SimpleMonitorState t = new SimpleMonitorState();
SimpleRunnable m = new SimpleRunnable(t);
Thread t1 = new Thread(m);
t1.start();
t.call();
}
public void call() throws InterruptedException {
synchronized (this) {
wait();
System.out.println("Single by Threads ");
}
}
}
class SimpleRunnable implements Runnable {
SimpleMonitorState t;
SimpleRunnable(SimpleMonitorState t) {
this.t = t;
}
@Override
public void run() {
try {
// Sleep
Thread.sleep(10000);
synchronized (this.t) {
this.t.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Thread.lassit () çağrısı, Thread.class nesnesinde senkronize edilen bir kod içinde anlamlıdır. Ne demek istediğini sanmıyorum.
Sen sor
Bildirilene kadar bir konuyu nasıl bekletebilirim?
Yalnızca geçerli iş parçacığınızı bekletebilirsiniz. Başka herhangi bir iş parçacığının kabul etmesi durumunda sadece hafifçe beklemesi istenebilir.
Bir koşul beklemek istiyorsanız, bir kilit nesnesine ihtiyacınız vardır - Thread.class nesnesi çok kötü bir seçimdir - tek bir AFAIK'tir, bu nedenle üzerinde senkronize etmek (Thread statik yöntemleri hariç) tehlikelidir.
Senkronizasyon ve bekleme detayları Tom Hawtin tarafından zaten açıklanmıştır.
java.lang.IllegalMonitorStateException
senkronize edilmediğiniz bir nesneyi beklemeye çalıştığınız anlamına gelir - bunu yapmak yasa dışıdır.
Bunun bir başkasına yardım edip etmeyeceğinden emin değilim ama bu, yukarıdaki kullanıcı "Tom Hawtin - tacklin" in cevabındaki sorunumu çözmenin kilit kısmıydı:
synchronized (lock) {
makeWakeupNeeded();
lock.notifyAll();
}
"Kilit" öğesinin senkronize () öğesinde argüman olarak iletilmesi ve "kilit" öğesinde de kullanılması .notifyAll ();
Bir kez bu 2 yerde yaptım Çalıştırdım
IllegalMonitorStateException
Farklı bir class
/ iş parçacığında / gelen bir iş parçacığını uyandırmaya çalışırken bir süre aldım . In java 8
size kullanabilirsiniz lock
yeni eşzamanlılık API özelliklerini yerine ait synchronized
fonksiyonlar.
Zaten asynchronous
websocket işlemleri için nesneleri bir WeakHashMap
. Benim durumumdaki çözüm aynı zamanda bir lock
nesneyiConcurrentHashMap
synchronous
yanıtlar için saklamaktı . Notcondition.await
(değil .wait
).
Çoklu iş parçacığı işlemek için Executors.newCachedThreadPool()
bir iş parçacığı havuzu oluşturmak için a kullandım .
Java 7.0 veya önceki sürümleri kullananlar, burada kullandığım koda başvurabilir ve çalışır.
public class WaitTest {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public void waitHere(long waitTime) {
System.out.println("wait started...");
lock.lock();
try {
condition.await(waitTime, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
lock.unlock();
System.out.println("wait ends here...");
}
public static void main(String[] args) {
//Your Code
new WaitTest().waitHere(10);
//Your Code
}
}