线程等待和释放的小麻烦(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对象来调用某个方法来改变另一个对象中的锁(这一点也说不通,我自己的锁凭什么让你来改)。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











Java でマルチスレッドを実装するには 2 つの方法があり、1 つは Thread クラスを継承する方法、もう 1 つは Runnable インターフェイスを実装する方法で、Thread クラスは java.lang パッケージで定義されます。クラスが Thread クラスを継承し、このクラスの run() メソッドをオーバーライドする限り、マルチスレッド操作を実装できますが、クラスが継承できる親クラスは 1 つだけであり、これがこのメソッドの制限です。例を見てみましょう: packageorg.thread.demo;classMyThreadextendsThread{privateStringname;publicMyThread(Stringname){super();this

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

オブジェクトからバイトへ、そしてバイトからオブジェクトへ 今日は、オブジェクトからバイトに変換する方法、およびバイトからオブジェクトに変換する方法を理解します。まず、クラス Student を定義します。 packagecom.byteToObject;importjava.io.Serializable;publicclassstudentimplementsSerializable{privateintsid;privateStringname;publicintgetSid(){returnsid;}publicvoidsetSid(in)

1. オブジェクト クラスの概要 オブジェクトは、Java によってデフォルトで提供されるクラスです。 Object クラスを除いて、Java のすべてのクラスには継承関係があります。デフォルトでは、Object 親クラスを継承します。つまり、Object のリファレンスを使用して、すべてのクラスのオブジェクトを受け取ることができます。例: Object を使用して、すべてのクラスのオブジェクトを受信します。 classperson{}classStudent{}publicclassTest{publicstaticvoidmain(String[]args){function(newperson());function(newStudent());}public

Java では、スレッドに関して言えば、Thread が不可欠です。スレッドは、プロセスよりも軽量なスケジュールされた実行プログラムです。なぜスレッドを使用するのでしょうか?スレッドを使用すると、オペレーティング システム プロセスでのリソース割り当てと実行スケジュールを分離できます。各スレッドはプロセス リソース (メモリ アドレス、ファイル I/O など) を共有できるだけでなく、独立してスケジュールすることもできます (スレッドは CPU スケジューリングの基本単位です)。注 1. Thread はスレッドを作成するための最も重要なクラスであり、単語自体もスレッドを表します。 2. Thread クラスは Runnable インターフェイスを実装します。インスタンス publicclassThreadDemoextendsThread{publicvoidrun(){for(inti=0)

新しいスレッドを開始するには、Java の Thread.start() 関数を使用します。Java では、マルチスレッドを使用して複数のタスクを同時に実行できます。 Java は、スレッドを作成および管理するための Thread クラスを提供します。 Thread クラスの start() 関数は、新しいスレッドを開始し、スレッドの run() メソッド内のコードを実行するために使用されます。コード例: publicclassMyThreadextendsThread{@Overr

PHP Notice: Tryingtogetpropertyofnon-object の解決策 PHP で開発しているときに、「 Notice: Tryingtogetpropertyofnon-object」というエラー メッセージが表示されることがあります。このエラー メッセージは、通常、初期化されていないオブジェクトを使用しているか、オブジェクトの参照が失われたために発生します。特定のコード部分に問題があり、プロパティに正しくアクセスできません。

Java では、Object クラスの getClass() 関数を使用して、オブジェクトのランタイム クラスを取得します。Java では、各オブジェクトには、オブジェクトのプロパティとメソッドを定義するクラスがあります。 getClass() 関数を使用して、オブジェクトのランタイム クラスを取得できます。 getClass() 関数は Object クラスのメンバー関数であるため、すべての Java オブジェクトがこの関数を呼び出すことができます。この記事では、getClass() 関数の使用方法といくつかのコード例を紹介します。取得を使用する
