我需要使用 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 语句。