线程等待和释放的小麻烦(wait/notify)
class ThreadA extends Thread{
//线程同步的公共数据区
Object oa=null;
ThreadA(Object o){
this.oa=o;
}
//线程A执行逻辑
public void run(){
//线程同步区域,需要申请公共数据的锁
synchronized(oa){
System.out.println("ThreadA is running......");
for(int i=0;i
System.out.println(" ThreadA value is "+i);
if(i==50){
try {
//当前线程等待
Thread.currentThread().wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}//if(i==50)
}//for(int i)
}
}
}
/**
* 线程B:等待线程A放弃锁,然后获得锁并执行,完成后唤醒线程A
*/
class ThreadB extends Thread{
//线程同步的公共数据区
Object ob=null;
ThreadB(Object o){
this.ob=o;
}
//线程B执行逻辑
public void run(){
//线程同步区域,需要申请公共数据的锁
synchronized(ob){
System.out.println("ThreadB is running......");
for(int i=0;i
System.out.println(" ThreadB value is "+i);
}
//唤醒等待的线程
notify();
}
}
}
//测试
public class ThreadTest {
public static void main(String[] args){
Object lock=new Object(); //公共数据区
ThreadA threada=new ThreadA(lock);
ThreadB threadb=new ThreadB(lock);
threada.start(); //线程A执行
threadb.start(); //线程B执行
}
} 程序很简单,就是让线程A,B交替打印。但是运行的时候会抛出两个异常:
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException: current thread not owner
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException: current thread not owner
问题就处在ThreadA中的Thread.currentThread().wait(); 和ThreadB中的notify();上。
初学者理解wait()的时候都认为是将当前线程阻塞,所以Thread.currentThread().wairt();视乎很有道理。但是不知道大家有没有发现,在JDK类库中wait()和notify()方法并不是Thread类的,而是Object()中的。我们仔细看看wait方法的JDK文档:
public final void wait() throws InterruptedException
Object (Java 2 Platform SE 6)
在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。 换句话说,此方法的行为就好像它仅执行 wait(0) 调用一样。
当前线程必须拥有此 对象监视器 。该线程发布对此监视器的所有权并等待 ,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。 然后该线程将等到重新获得对监视器的所有权后才能继续执行。
对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用:
synchronized (obj) {
while (
obj.wait();
// Perform action appropriate to condition
}
此方法只应由作为此对象监视器的所有者的线程来调用。
抛出: IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。
InterruptedException - 如果在当前线程等待通知之前或者正在等待通知时,任何线程中断了当前线程。在抛出此异常时,当前线程的中断状态 被清除。
看完JDK文档以后,很显然,只要把开始的程序中Thread.currentThread().wait();改成oa.wait() 。 notify();改成 ob.notify()就没有问题了。
也就是说,只能通过同步块obj来调用wait/notify方法 ,而不能通过想当然的线程调用这两个方法。至于为什么是这样,我有一种想法,大家可以一起讨论一下:
首先,我们都知道JVM会给每一个对象都分配唯一的一把锁。这把锁是在对象中的。
然后,当Thread-0线程获得了这把锁后,应该是在对象中的锁内记录下当前占有自己的线程号,并把自己设置为已被占用。那么当Thread-0需要放弃锁的时候,锁对象会吧 Thread-0放入到锁的等待队列中 。而这一切和Thread-0是没有任何关系的。自然也轮不到Thread-0对象来调用某个方法来改变另一个对象中的锁(这一点也说不通,我自己的锁凭什么让你来改)。

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Il existe deux façons d'implémenter le multithreading en Java, l'une consiste à hériter de la classe Thread et l'autre à implémenter l'interface Runnable ; la classe Thread est définie dans le package java.lang. Tant qu'une classe hérite de la classe Thread et remplace la méthode run() dans cette classe, elle peut implémenter des opérations multithread. Cependant, une classe ne peut hériter que d'une seule classe parent, ce qui constitue une limitation de cette méthode. Regardons un exemple : packageorg.thread.demo;classMyThreadextendsThread{privateStringname;publicMyThread(Stringname){super();this

php提交表单通过后,弹出的对话框怎样在当前页弹出php提交表单通过后,弹出的对话框怎样在当前页弹出而不是在空白页弹出?想实现这样的效果:而不是空白页弹出:------解决方案--------------------如果你的验证用PHP在后端,那么就用Ajax;仅供参考:HTML code

Objet en octet et octet en objet Aujourd'hui, nous allons comprendre comment convertir un objet en octet et comment convertir un octet en objet. Tout d'abord, définissez un élève de classe : packagecom.byteToObject;importjava.io.Seriallessly;publicclassstudentimplementsSerializing{privateintsid;privateStringname;publicintgetSid(){returnsid;}publicvoidsetSid(in

1. Introduction à la classe Object Object est une classe fournie par Java par défaut. À l'exception de la classe Object, toutes les classes Java ont des relations d'héritage. Par défaut, il héritera de la classe parent Object. Autrement dit, les objets de toutes les classes peuvent être reçus en utilisant la référence Object. Exemple : utilisez Object pour recevoir des objets de toutes les classes classPerson{}classStudent{}publicclassTest{publicstaticvoidmain(String[]args){function(newPerson());function(newStudent());}public

Utilisez la fonction Thread.start() de Java pour démarrer un nouveau thread En Java, nous pouvons utiliser le multithreading pour exécuter plusieurs tâches simultanément. Java fournit la classe Thread pour créer et gérer des threads. La fonction start() de la classe Thread est utilisée pour démarrer un nouveau thread et exécuter le code dans la méthode run() du thread. Exemple de code : publicclassMyThreadextendsThread{@Overr

En Java, lorsqu'il s'agit de threads, Thread est essentiel. Un thread est un exécuteur planifié plus léger qu’un processus. Pourquoi utiliser des fils de discussion ? En utilisant des threads, vous pouvez séparer l'allocation des ressources et la planification de l'exécution dans les processus du système d'exploitation. Chaque thread peut non seulement partager des ressources de processus (adresse mémoire, E/S de fichier, etc.), mais peut également être planifié indépendamment (les threads sont l'unité de base de la planification du processeur). Remarque 1. Thread est la classe la plus importante pour créer des threads, et le mot lui-même représente également thread. 2. La classe Thread implémente l'interface Runnable. Instance publicclassThreadDemoextendsThread{publicvoidrun(){for(inti=0

Java utilise la fonction getClass() de la classe Object pour obtenir la classe d'exécution de l'objet. En Java, chaque objet possède une classe qui définit les propriétés et les méthodes de l'objet. Nous pouvons utiliser la fonction getClass() pour obtenir la classe d'exécution d'un objet. La fonction getClass() est une fonction membre de la classe Object, tous les objets Java peuvent donc appeler cette fonction. Cet article explique comment utiliser la fonction getClass() et donne quelques exemples de code. utiliser obtenir

La relation entre les types de données de base et Object. Je sais que tout le monde a entendu dire que Object est la classe de base de tous les types, mais cette phrase n'est en fait pas correcte, car les types de données de base en Java n'ont rien à voir avec Object. Par exemple, lorsque vous appelez la méthode swap, vous ne pouvez pas transmettre directement le type int à la méthode swap(Objectobj), car Object n'a en fait rien à voir avec le type de données de base. À ce stade, a constate que nos types ne correspondent pas. il l'enveloppe donc automatiquement. Il est devenu un type Integer. À ce stade, il peut être contacté avec Object et la méthode swap peut être appelée avec succès Object, une classe wrapper de types de données de base.
