Java 一个线程中的非空值,在另一个线程中为空

Java 一个线程中的非空值,在另一个线程中为空,java,multithreading,vert.x,blockingqueue,Java,Multithreading,Vert.x,Blockingqueue,我正在用Java开发一个多客户端TCP服务器。由于服务器必须能够同时执行许多操作,因此我创建了一个线程,用于通过套接字向客户端发送数据。其定义如下: public class MessageSender implements Runnable{ private OutputStream output; private volatile ArrayList<byte[]> messagesToSend; public MessageSender(Output

我正在用Java开发一个多客户端TCP服务器。由于服务器必须能够同时执行许多操作,因此我创建了一个线程,用于通过套接字向客户端发送数据。其定义如下:

public class MessageSender implements Runnable{

    private OutputStream output;
    private volatile ArrayList<byte[]> messagesToSend;

    public MessageSender(OutputStream _output)
    {
        output = _output;
        messagesToSend = new ArrayList<byte[]>(0);
    }

    public void run()
    {
        while (true)
        {
           if (messagesToSend.size() > 0)
           {
               sendMessage(messagesToSend.get(0));
               messagesToSend.remove(0);
           }
        }
    }

    public void setMessageToSend(Message message)
    {
        messagesToSend.add(message.getMessageHandler().getBytes());
    }

    public void sendMessage(byte[] bytes)
    {
        if (bytes == null)
        {
            System.out.println("bytes = null");
            return ;
        }
        try
        {
            output.write(bytes, 0, bytes.length);
        }
        catch (IOException e)
        {
            System.out.println(e);
        }
    }
}
这是一个
Vertx
处理程序,在从客户端接收特定消息时只调用一次。它被调用,通道_状态按预期实例化。在同一个线程中,我有一个Vertx计时器,在该计时器中,我向
MessageSender
发送一个由channel\u status类包含的字节数组

vertx.setPeriodic(duration, id -> {
    System.out.println(Arrays.toString(channel_test.getMessageHandler().getBytes()));
    sender.setMessageToSend(channel_test);
});
如您所见,我正在打印它的值,以确保它不为null。而且,它在计时器中从不为空。但是当MessageSender收到它时,有时它是空的(有时我指的是大约1/50次)。为什么?这是一个并发问题吗


谢谢。

将您的
运行方法更改为

public void run() {
    while (true) {
        synchronized(messagesToSend) {
           while (messagesToSend.isEmpty()) {
               messagesToSend.wait();
           }
        }
        sendMessage(messagesToSend.get(0));
        messagesToSend.remove(0);
   }
}

setMessageToSend()
as

public void setMessageToSend(Message message) {
    messagesToSend.add(message.getMessageHandler().getBytes());
    messagesToSend.notify();
}

run
方法更改为

public void run() {
    while (true) {
        synchronized(messagesToSend) {
           while (messagesToSend.isEmpty()) {
               messagesToSend.wait();
           }
        }
        sendMessage(messagesToSend.get(0));
        messagesToSend.remove(0);
   }
}

setMessageToSend()
as

public void setMessageToSend(Message message) {
    messagesToSend.add(message.getMessageHandler().getBytes());
    messagesToSend.notify();
}
使
ArrayList
volatile
保证在thread1中添加新元素时,thread2可以看到它

您应该使用支持的列表,例如:

messagesToSend  = Collections.synchronizedList(new ArrayList<byte[]>(0));
A可以解决这个问题:

private BlockingQueue<byte[]> messagesToSend;

public MessageSender(OutputStream _output) {
    output = _output;
    messagesToSend = new LinkedBlockingQueue<>();
}

public void run() {
    while (true) {
        try {
            sendMessage(messagesToSend.take());  // this will get blocked untill the queue is not empty
        } catch (InterruptedException e) {

        }
    }
}

public void setMessageToSend(Message message) {
    try {
        messagesToSend.put(message.getMessageHandler().getBytes()); // put new element in the queue, check if run method is blocked, wake it up
    } catch (InterruptedException e) {

    }
}
private BlockingQueue messagesToSend;
public MessageSender(OutputStream\u输出){
输出=_输出;
messagesToSend=newlinkedblockingqueue();
}
公开募捐{
while(true){
试一试{
sendMessage(messagesToSend.take());//这将被阻止,直到队列不为空为止
}捕捉(中断异常e){
}
}
}
公共无效setMessageToSend(消息消息){
试一试{
messagesToSend.put(message.getMessageHandler().getBytes());//将新元素放入队列,检查run方法是否被阻止,将其唤醒
}捕捉(中断异常e){
}
}
制作
ArrayList
volatile
确保在thread1中添加新元素时,thread2可以看到它

您应该使用支持的列表,例如:

messagesToSend  = Collections.synchronizedList(new ArrayList<byte[]>(0));
A可以解决这个问题:

private BlockingQueue<byte[]> messagesToSend;

public MessageSender(OutputStream _output) {
    output = _output;
    messagesToSend = new LinkedBlockingQueue<>();
}

public void run() {
    while (true) {
        try {
            sendMessage(messagesToSend.take());  // this will get blocked untill the queue is not empty
        } catch (InterruptedException e) {

        }
    }
}

public void setMessageToSend(Message message) {
    try {
        messagesToSend.put(message.getMessageHandler().getBytes()); // put new element in the queue, check if run method is blocked, wake it up
    } catch (InterruptedException e) {

    }
}
private BlockingQueue messagesToSend;
public MessageSender(OutputStream\u输出){
输出=_输出;
messagesToSend=newlinkedblockingqueue();
}
公开募捐{
while(true){
试一试{
sendMessage(messagesToSend.take());//这将被阻止,直到队列不为空为止
}捕捉(中断异常e){
}
}
}
公共无效setMessageToSend(消息消息){
试一试{
messagesToSend.put(message.getMessageHandler().getBytes());//将新元素放入队列,检查run方法是否被阻止,将其唤醒
}捕捉(中断异常e){
}
}

不应该等待并在两个不同的线程中调用notify吗?
setMessageToSend
是通过另一个线程调用的,因此notify将在另一个线程中调用,当另一个线程调用wait时,
wait
notify
工作在
synchronized
方法或块不应该在两个不同的线程中调用wait和notify?
setMessageToSend
是通过另一个线程调用的,因此notify将在另一个线程上调用,while wait由另一个调用
wait
notify
synchronized
方法中工作,或者blockwait和notify在while中仍然需要较少的cpu周期loop@HemantPatel是,需要
等待
通知
。我认为
阻塞队列
比呼叫
等待
通知
更干净。不过有一个问题。BlockingQueue是一个抽象类,不能实例化,对吗?也许我应该使用LinkedBlockingQueue?等待并通知仍需要较少的cpu周期loop@HemantPatel是,需要
等待
通知
。我认为
阻塞队列
比呼叫
等待
通知
更干净。不过有一个问题。BlockingQueue是一个抽象类,不能实例化,对吗?也许我应该使用LinkedBlockingQueue?