关于空引用的问题

2020-12-25 20:15:37 +08:00
 QBugHunter

这里有个套接字类,用于发送消息,我使用了一个 List 来储存消息,然后用一个无线循环来发送消息,首先每个消息都设为一个类

public class SocketMsg{
    public String ip;
    public int port;
    public byte[] msg;
};

然后我在某个单例类里有一个 List<SocketMsg>来储存要发送的消息,该类由一个函数,添加消息,整个程序都会用通过这个函数添加消息,类似下面的代码

public MyUdpSocket{
    private MyUdpSocket mySocket = null;
    public static MyUdpSocket getInstance(){
        if(mySocket == null)
            mySocket = new MyUdpSocket();
    };
    
    private List<SocketMsg> msgQueue = new AtrrayList<>();
    
    public addMsgToQueue(SocketMsg msg){
        msgQueque.add(msg);
    };
};

然后这个 MyUdpSocket 类里还有个内部类,该类继承 Thread,类似下面代码

private class SendThread extends Thread {
    private SendThread() {
    }
    @Override
    public void run() {
        while (true) {
        if (udpSocket == null || udpSocket.isClosed()) {return;}
        if(msgQueue.size() == 0) continue;
         try {
             SendMsg sendMsg = msgQueue.get(0);
             InetAddress devAddress = InetAddress.getByName(sendMsg.IP);
             DatagramPacket mDatagram = new DatagramPacket(sendMsg.Msg, sendMsg.Msg.length, devAddress, sendMsg.Port);
             udpSocket.send(mDatagram);
             msgQueue.remove(0);  //唯一的 remove
             } catch (Exception e) {
                    Log.d("sendMsg", "--消息发送失败--" + e);
             }
        }
    }
}

首先,msgQueue 唯一的一个 remove()就在此处,程序的其他地方只有 add(),然后这个队列我采取发送第一个,然后删除第一个的方式

然后,程序随机的会报异常 java.lang.NullPointerException: Attempt to read from field 'java.lang.String com.wawa.MySocket.SendMsg.IP' on a null object reference

注意合格异常是随机的,大概 3-5 条消息,就会报一条

我想问下,这个大概是那里错了,我每次发送前都会检查 msgQueue 的 size(),如果为 0 就 continue,而且我反复确认,程序里 msgQueue 只有唯一的一处 remove(),我想问下,这个一般是什么情况

4601 次点击
所在节点    Android
8 条回复
guchengyehai1
2020-12-25 20:35:21 +08:00
Queue 非线程安全容器
LGA1150
2020-12-25 20:39:02 +08:00
List 非线程安全
QBugHunter
2020-12-25 20:41:32 +08:00
@guchengyehai1
我用的是 List


@LGA1150
但其他线程只会 add(),整个程序唯一的一个 remove()就是我示例代码里的,这个我和同事都反复确认过了
LGA1150
2020-12-25 20:46:44 +08:00
@QBugHunter 如果把 ArrayList 换成 Vector 还会出错吗?
ssynhtn
2020-12-25 21:00:01 +08:00
@QBugHunter 两个线程同时 add,会把 msg 加到 arraylist 同一位,两个都对 size 加 1,导致有一位上的 msg 为 null
Lemeng
2020-12-25 23:54:59 +08:00
非线程
liufish
2020-12-26 15:20:23 +08:00
子线程直接死循环有点太猛了。
List 换成 BlockingQueue,按生产-消费模式来做试试?
twoyuan
2020-12-26 23:45:43 +08:00
因为 msgQueue.size() 和下面的 msgQueue.get(0) 不是原子化操作,也就是上面说的线程不安全,多线程环境下 size() 后 get() 之前发生了 remove

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/739023

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX