线程等待和释放的小麻烦(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 Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Java에서 멀티스레딩을 구현하는 방법에는 두 가지가 있습니다. 하나는 Thread 클래스를 상속하는 것이고, 다른 하나는 Runnable 인터페이스를 구현하는 것입니다. Thread 클래스는 java.lang 패키지에 정의되어 있습니다. 클래스가 Thread 클래스를 상속하고 이 클래스의 run() 메서드를 재정의하는 한 다중 스레드 작업을 구현할 수 있습니다. 그러나 클래스는 하나의 상위 클래스만 상속할 수 있으며 이는 이 메서드의 제한 사항입니다. 예를 살펴보겠습니다: packageorg.thread.demo;classMyThreadextendsThread{privateStringname;publicMyThread(Stringname){super();this

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

Object에서 byte로, byte에서 Object로 오늘은 Object에서 byte로 변환하는 방법과 byte에서 Object로 변환하는 방법을 알아보겠습니다. 먼저 학생 클래스를 정의합니다. packagecom.byteToObject;importjava.io.Serialized;publicclassstudentimplementsSerialized{privateintsid;privateStringname;publicintgetSid(){returnsid;}publicvoidsetSid(in

1. Object 클래스 소개 Object는 Java에서 기본적으로 제공하는 클래스입니다. Object 클래스를 제외한 Java의 모든 클래스는 상속 관계를 갖습니다. 기본적으로 Object 상위 클래스를 상속합니다. 즉, Object의 참조를 이용하여 모든 클래스의 객체를 받을 수 있습니다. 예: Object를 사용하여 모든 클래스의 객체 수신 classPerson{}classStudent{}publicclassTest{publicstaticvoidmain(String[]args){function(newPerson());function(newStudent());}public

Java의 Thread.start() 함수를 사용하여 새 스레드를 시작합니다. Java에서는 멀티스레딩을 사용하여 여러 작업을 동시에 실행할 수 있습니다. Java는 스레드를 생성하고 관리하기 위한 Thread 클래스를 제공합니다. Thread 클래스의 start() 함수는 새 스레드를 시작하고 스레드의 run() 메서드에 있는 코드를 실행하는 데 사용됩니다. 코드 예: publicclassMyThreadextendsThread{@Overr

자바에서는 쓰레드에 있어서 쓰레드(Thread)가 필수적이다. 스레드는 프로세스보다 더 가벼운 예약 실행자입니다. 스레드를 사용하는 이유는 무엇입니까? 스레드를 사용하면 운영 체제 프로세스에서 리소스 할당과 실행 일정을 분리할 수 있습니다. 각 스레드는 프로세스 리소스(메모리 주소, 파일 I/O 등)를 공유할 수 있을 뿐만 아니라 독립적으로 예약할 수도 있습니다(스레드는 CPU 예약의 기본 단위입니다). 참고 1. Thread는 Thread를 만드는 데 가장 중요한 클래스이며, 단어 자체도 Thread를 나타냅니다. 2. Thread 클래스는 Runnable 인터페이스를 구현합니다. 인스턴스 publicclassThreadDemoextendsThread{publicvoidrun(){for(inti=0

Java는 Object 클래스의 getClass() 함수를 사용하여 객체의 런타임 클래스를 얻습니다. Java에서 각 객체에는 객체의 속성과 메서드를 정의하는 클래스가 있습니다. getClass() 함수를 사용하여 객체의 런타임 클래스를 가져올 수 있습니다. getClass() 함수는 Object 클래스의 멤버 함수이므로 모든 Java 객체가 이 함수를 호출할 수 있습니다. 이 기사에서는 getClass() 함수를 사용하는 방법을 소개하고 몇 가지 코드 예제를 제공합니다. get을 사용하세요

기본 데이터 유형과 Object 사이의 관계 Object가 모든 유형의 기본 클래스라는 것을 누구나 들어봤을 것입니다. 그러나 이 문장은 실제로 정확하지 않습니다. 왜냐하면 Java의 기본 데이터 유형은 Object와 관련이 없기 때문입니다. 예를 들어 swap 메소드를 호출할 때 실제로 Object는 기본 데이터 유형과 아무 관련이 없기 때문에 int 유형을 swap(Objectobj) 메소드에 직접 전달할 수 없습니다. 이제 자동으로 Wrapping하게 되어 Integer 타입이 되었고, 기본 데이터 타입의 래퍼 클래스인 Swap 메소드를 성공적으로 호출할 수 있게 되었습니다.
