如何解决实现 Runnable 未显示正确结果
我试图在一个类上使用 wait() 和 notify() 来通知等待线程,但场景是先进入同步块的人将等待其他人打印一些值并通知等待线程。但等待线程一直在等待。做错了什么。
public class MyRunnableClass implements Runnable {
public static boolean transfer = false;
public static boolean isAnyThreadWaiting = false;
int a=10;
@Override
public void run() {
// Todo Auto-generated method stub
synchronized(this) {
System.out.println("I am Thread : "+Thread.currentThread().getName()+" and I first occuipied block");
try {
if(isAnyThreadWaiting)
MyRunnableClass.transfer=true;
if(!MyRunnableClass.transfer&&!isAnyThreadWaiting) {
System.out.println("I am Thread : "+Thread.currentThread().getName()+" and I am going to wait");
while(!MyRunnableClass.transfer) {
isAnyThreadWaiting=true;
this.wait();
}
}
} catch (InterruptedException e) {
// Todo Auto-generated catch block
e.printstacktrace();
}
for(int i=0; i<a;i++) {
System.out.println("I am Thread : "+Thread.currentThread().getName()+" Value of a is : "+i );
}
a=0;
isAnyThreadWaiting=false;
this.notify();
}
}
public static void main(String [] args) throws InterruptedException {
MyRunnableClass runnable1= new MyRunnableClass();
Thread thread1=new Thread(runnable1,"t1");
Thread thread2=new Thread(runnable1,"t2");
thread1. start();
thread2. start();
}
}
解决方法
synchronized(this)
this
在您的两个线程中是相同的,因为您使用了相同的 Runnable
实例。 synchronized
确保两个线程不能同时在块内。这意味着一个线程位于 synchronized
块的开头,另一个位于 wait
。您需要将同步范围缩小到实际使用共享状态的地方,即仅synchronized(this)
实际引用(读取或写入)变量的代码两个线程都需要。
我已经调试了你的代码并找到了原因:
a=0;
请删除此代码,您将看到两个线程的输出:
I am Thread : t1 and I first occuipied block
I am Thread : t1 and I am going to wait
I am Thread : t2 and I first occuipied block
I am Thread : t2 Value of a is : 0
I am Thread : t2 Value of a is : 1
I am Thread : t2 Value of a is : 2
I am Thread : t2 Value of a is : 3
I am Thread : t2 Value of a is : 4
I am Thread : t2 Value of a is : 5
I am Thread : t2 Value of a is : 6
I am Thread : t2 Value of a is : 7
I am Thread : t2 Value of a is : 8
I am Thread : t2 Value of a is : 9
I am Thread : t1 Value of a is : 0
I am Thread : t1 Value of a is : 1
I am Thread : t1 Value of a is : 2
I am Thread : t1 Value of a is : 3
I am Thread : t1 Value of a is : 4
I am Thread : t1 Value of a is : 5
I am Thread : t1 Value of a is : 6
I am Thread : t1 Value of a is : 7
I am Thread : t1 Value of a is : 8
I am Thread : t1 Value of a is : 9
附言您示例中的第二个线程实际上不会进入 wait() 状态。
但是因为您在第二个线程中将 a 设置为 0,所以第一个线程跳过了这个循环:
for(int i=0; i<a;i++) {
System.out.println("I am Thread : "+Thread.currentThread().getName()+" Value of a is : "+i );
}
这就是为什么你看不到第一个线程的输出。但它并没有停留在 wait() 状态。
,在一个线程中对静态变量所做的更改对另一个线程不可见。因此,对于两个线程,始终是transfer == false 和 isAnyThreadWaiting == false。
这意味着两个线程都进入“wait()”块并永远停留在那里。
因为您要尝试对静态变量进行同步,所以您必须使用同步静态方法。
在此处查看更多详细信息: How to synchronize a static variable among threads running different instances of a class in Java?
但更简单的解决方案是根本不使用静态变量。 在您的情况下,您对两个线程使用相同的对象,因此无论如何都不需要将变量设为静态:
private boolean transfer = false;
private boolean isAnyThreadWaiting = false;
完整的解决方案应如下所示:
public class MyRunnableClass implements Runnable {
private boolean transfer = false;
private boolean isAnyThreadWaiting = false;
int a=10;
@Override
public void run() {
// TODO Auto-generated method stub
synchronized(this) {
System.out.println("I am Thread : "+Thread.currentThread().getName()+" and I first occuipied block");
try {
if(isAnyThreadWaiting)
transfer=true;
if(!transfer && !isAnyThreadWaiting) {
System.out.println("I am Thread : "+Thread.currentThread().getName()+" and I am going to wait");
while(!transfer) {
isAnyThreadWaiting=true;
this.wait();
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i=0; i<a;i++) {
System.out.println("I am Thread : "+Thread.currentThread().getName()+" Value of a is : "+i );
}
a=0;
isAnyThreadWaiting=false;
this.notify();
}
}
public static void main(String [] args) throws InterruptedException {
MyRunnableClass runnable1= new MyRunnableClass();
Thread thread1=new Thread(runnable1,"t1");
Thread thread2=new Thread(runnable1,"t2");
thread1. start();
thread2. start();
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。