gpt4 book ai didi

java - 线程问题 - 接收方在发送方之前打印

转载 作者:行者123 更新时间:2023-12-02 01:15:33 25 4
gpt4 key购买 nike

我试图找出java中的线程,并试图理解我得到的输出。我创建了 3 个类:发送者、接收者和消息框。

我正在尝试通过消息框将数据从发送者发送到接收者。当发送方发送数据时,它会打印“发送方放置元素”。一旦接收者获得了一个元素,它就会打印“接收者获得了元素”

问题是,在控制台中,我看到接收者在发送者打印出他发送元素之前打印出他已获取该元素..

发件人:

public class Sender implements Runnable {
private MessageBox msgBox;

public Sender(MessageBox m)
{
msgBox=m;
}

public void run()
{
Thread.currentThread().setName("Sender");
for(int i=0;i< 100;i++)
{
msgBox.put(i);
System.out.println("Sender put element : " + i);
try {
long sleep_time = (long)(Math.random()*5000);
//System.out.println("Sender going to sleep for " + sleep_time + " ms");
Thread.sleep(sleep_time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

接收者:

public class Receiver implements Runnable{

private MessageBox<Integer> msgBox;

public Receiver(MessageBox<Integer>m)
{
msgBox = m;
}

public void run()
{
Thread.currentThread().setName("Receiver");
while(true)
{
int element = msgBox.get();
System.out.println("Receiver got element : " + element);
try
{
long sleep_time = (long)(Math.random()*5000);
//System.out.println("Receiver going to sleep for " + sleep_time + " ms");
Thread.sleep(sleep_time);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}


}
}

消息框:

import java.util.LinkedList;
import java.util.Queue;

public class MessageBox<E> {

private Queue<E> msgQ;

public MessageBox()
{
msgQ = new LinkedList<>();
}

public synchronized void put(E i)
{
msgQ.add(i);
notify();
System.out.println(Thread.currentThread().getName() + " : notifying other threads...");

}

public synchronized E get()
{
if(msgQ.isEmpty())
{
try
{
System.out.println(Thread.currentThread().getName() + " : waiting for new element..");
notify();
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}

return msgQ.remove();
}

public boolean isEmpty()
{
return msgQ.isEmpty();
}


}

主要:

public class Main {

public static void main(String[]args)
{
MessageBox msgBox = new MessageBox<Integer>();
Sender sender = new Sender(msgBox);
Receiver receiver = new Receiver(msgBox);

Thread t1 = new Thread(sender);
Thread t2 = new Thread(receiver);

t1.start();
t2.start();


}
}

控制台:

Receiver : waiting for new element..
Sender : notifying other threads...
Receiver got element : 0
Sender put element : 0
....

另外,我需要将messagebox中的Q设置为 volatile 吗?

最佳答案

你的代码没问题。您看到的输出可能会发生,因为插入到 messageBox 并打印消息不是原子的。

您在 Sender 中的代码可以像这样被拦截:

  Sender Thread                              Receiver Thread

msgBox.put(i);
int element = msgBox.get();
System.out.println("Receiver got element : " + element);
System.out.println("Sender put element : " + i);

因此,在发送方放置元素之后、发送方打印消息之前,接收方能够先获取该元素并打印消息,因为它在另一个线程中运行。在发送者将元素放入 messageBox 之前放置消息没有帮助,因为这样它可能会以另一种方式不一致:它打印元素已添加的消息,但由于某些原因不必实际添加异常。

如果您确实想要有序地放置/接收消息,则必须将该消息放入 MessogeBox 方法中,如下所示:

public synchronized void put(E i)
{
msgQ.add(i);
System.out.println("Sender put element : " + i);
notify();
System.out.println(Thread.currentThread().getName() + " : notifying other threads...");

}



public synchronized E get()
{
if(msgQ.isEmpty())
{
try
{
System.out.println(Thread.currentThread().getName() + " : waiting for new element..");
notify();
wait();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}

return msgQ.remove();
}

如果您仅在同步锁下访问 msgQ,则不必将 msgQ 设置为 volatile 。您还必须将 isEmpty 方法设置为同步,然后不必将 msgQ 设置为 volatile 。因此,请像这样修复您的代码:

  public synchronized boolean isEmpty()
{
return msgQ.isEmpty();
}

关于java - 线程问题 - 接收方在发送方之前打印,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58673390/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com