使用 wait() 和 notify() 进行同步



我需要使用 3 个不同的线程打印以下模式,以便:

线程 1 打印"I">

线程 2 打印"爱">

线程 3 打印"地球"

I LOVE EARTH
I LOVE EARTH
I LOVE EARTH

使用 wait(( 和 notify(( 方法。 我从以下代码开始,但似乎它只打印一次,因为它们都在等待每个循环的第一次迭代结束时。

public class MultiThreading_2 {
static volatile boolean flag=false;
static volatile String  word = "I";

public static void main(String[] args) throws InterruptedException {
MultiThreading_2 m = new MultiThreading_2();

Runnable a = new Runnable() {
public void run() {
if(word.equals("I"))
{
synchronized(m)
{
for(int i=1;i<=2;i++) {
if(word.equals("I"))    {   
System.out.println("I ");
word="LOVE";
try {
m.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
m.notify();
}
}
}
}

};
Runnable b = new Runnable() {
public void run() {
if(word.equals("LOVE"))
{
synchronized(m)
{
for(int j=1;j<=2;j++) {
if(word.equals("LOVE")) {
System.out.println("LOVE ");
word="WORLD";
try {
m.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
m.notify();

}
}

}
}
}

};
Runnable c = new Runnable() {
public void run() {
if(word.equals("WORLD"))
{
synchronized(m)
{
for(int k=1;k<=2;k++) {
System.out.println("WORLD ");
word="I";
try {
m.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
m.notify();

}

}
}
}

};

new Thread(a).start();
Thread.sleep(100);
new Thread(b).start();
Thread.sleep(100);
new Thread(c).start();
}

}

有人可以解释一下如何解决这个问题吗?

我已经修复了你的代码。你把"m.notify(("放在"m.wait(("之后,所以它们都互相等待。我轻轻地将它移到"m.wait(("之前,并将 for 循环转换为无限 while 循环,以使线程永远运行。

更新1

我已经更新了代码,以便线程将文本写入三次。

public class MultiThreading_2 {
static volatile boolean flag = false;
static volatile String word = "I";
public static void main(String[] args) throws InterruptedException {
MultiThreading_2 m = new MultiThreading_2();
Runnable a = new Runnable() {
public void run() {
for (int i = 0; i < 3; i++) {
synchronized (m) {
if (word.equals("I")) {
System.out.print("I ");
word = "LOVE";
m.notify();
try {
m.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
i--;
}
}
}
}
};
Runnable b = new Runnable() {
public void run() {
for (int i = 0; i < 3; i++) {
synchronized (m) {
if (word.equals("LOVE")) {
System.out.print("LOVE ");
word = "WORLD";
m.notify();
try {
m.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
i--;
}
}
}
}
};
Runnable c = new Runnable() {
public void run() {
for (int i = 0; i < 3; i++) {
synchronized (m) {
if (word.equals("WORLD")) {
System.out.println("WORLD ");
word = "I";
m.notify();
try {
m.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
i--;
}
}
}
}
};
new Thread(a).start();
Thread.sleep(100);
new Thread(b).start();
Thread.sleep(100);
new Thread(c).start();
}
}

Object.notify()随机选择一个线程来唤醒。由于启动之间的睡眠,您的代码只能工作一次,您可以人为地确保预期的执行顺序。

你应该使用notifyAll(),唤醒所有线程,因此,线程应该循环wait(),直到轮到它们:

Runnable a = new Runnable() {
public void run() {
synchronized (m) {
for (int i = 1; i <= 2; i++) {
while(!word.equals("I"))
try{
m.wait();
}
catch(InterruptedException ie){
ie.printStackTrace();
}
System.out.print("I ");
word = "LOVE";
m.notifyAll();
}
}
}
};
Runnable b = new Runnable() {
public void run() {
synchronized (m) {
for (int i = 1; i <= 2; i++) {
while(!word.equals("LOVE"))
try{
m.wait();
}
catch(InterruptedException ie){
ie.printStackTrace();
}
System.out.print("LOVE ");
word = "WORLD";
m.notifyAll();
}
}
}
};
Runnable c = new Runnable() {
public void run() {
synchronized (m) {
for (int i = 1; i <= 2; i++) {
while(!word.equals("WORLD"))
try{
m.wait();
}
catch(InterruptedException ie){
ie.printStackTrace();
}
System.out.println("WORLD ");
word = "I";
m.notifyAll();
}
}
}
};
new Thread(a).start();
new Thread(b).start();
new Thread(c).start();

从一开始就删除了if,因为在实际并发执行中,不能保证在word中具有预期值。然后其中一个线程抓住锁,检查word是否是它自己的,然后开始等待,或者打印其文本并word步到下一阶段,唤醒其他线程(它们都是,带有notifyAll()(。然后它要么退出,要么再次进入wait()。这是一个重要的部分:我想尽可能少地修改你的代码,所以一切都发生在同步块内,这意味着线程只能在其他两个等待或完成时运行。对于这个锁步,它可以工作,但一般来说,同步块应该在 for 循环内,也许是两个单独的块,一个围绕 equals-wait 循环,另一个围绕 set+notifyAll 语句。

最新更新