Java 服务器中出现空指针异常

Java 服务器中出现空指针异常,java,multithreading,nullpointerexception,Java,Multithreading,Nullpointerexception,这是一个客户机-服务器程序。 对于每个客户端,服务器都有一个方法,用于检查是否有一些消息发送到此客户端 代码: id-整数。 这真的很奇怪,因为我在调试这一部分中运行并检查了“base”和“id”是否为null,以及base是否有适当的字段。 基地不是空的 顺便说一下,base是静态的(因为每个线程都可以使用它),并且在使用此方法之前声明了base 这条线不会引起问题 for(int j = 0;j<Start.bases.size();j++){ 有什么问题 编

这是一个客户机-服务器程序。 对于每个客户端,服务器都有一个方法,用于检查是否有一些消息发送到此客户端

代码:

id-整数。 这真的很奇怪,因为我在调试这一部分中运行并检查了“base”和“id”是否为null,以及base是否有适当的字段。 基地不是空的

顺便说一下,base是静态的(因为每个线程都可以使用它),并且在使用此方法之前声明了base

这条线不会引起问题

            for(int j = 0;j<Start.bases.size();j++){
有什么问题

编辑

  static ArrayList<Base> bases;
  bases = new ArrayList<Base>();
静态数组列表基;
bases=新的ArrayList();
类库:

 public class Base {
private ServerThread st;
private int id;
private String name;
private ArrayList<String> messages;

public Base(String n, ServerThread s_t, int i_d){
    messages = new ArrayList<String>();
    st = s_t;
    name = n;
    id = i_d;
}

public String getName(){
    return name;
}
public int getId(){
    return id;
}
public ServerThread getThr(){
    return st;
}
public String getMessage(){
    String ret = "";

    if(!messages.isEmpty()){
        ret = messages.get(0);
        messages.remove(messages.get(0));
    }

    return ret;
}

public void addMessage(String m){
    messages.add(m);
}

public boolean ifEmpty(){
    return messages.isEmpty();
}
  }
公共类基{
私有线程st;
私有int-id;
私有字符串名称;
私有数组列表消息;
公共基(字符串n、服务器线程s\u t、整数i\u d){
messages=newarraylist();
st=s_t;
name=n;
id=i_d;
}
公共字符串getName(){
返回名称;
}
公共int getId(){
返回id;
}
公共服务器线程getThr(){
返回st;
}
公共字符串getMessage(){
字符串ret=“”;
如果(!messages.isEmpty()){
ret=messages.get(0);
messages.remove(messages.get(0));
}
返回ret;
}
公共void addMessage(字符串m){
添加(m);
}
公共布尔值ifEmpty(){
返回消息。isEmpty();
}
}
谢谢。

在这行代码中: (Start.base.get(j).getId()==id

在以下情况下,您可能会有此类例外:

1) bases is null - you said its wrong
2) bases.get(j) - it may occur only if you collection size was reduced during iteration(as mentioned Gray)
3) Start.bases.get(j).getId() is null. But as you mentioned getId() method return primitive int, so its not the case as in this situation you receive null ponter while casting - in line "    return id;".
因此,您应该检查第二种情况。

鉴于此:

我已在调试此部件中运行,并检查了“base”和“id”是否不为null,以及base是否有适当的字段

这是:

bases是静态的(因为每个线程都可以使用它)

我认为很有可能存在争用条件。在争用条件下,有两个线程同时访问同一数据结构(在本例中为Start.base)。大多数情况下,一个线程的代码完成得更快,一切都按照您期望的方式进行,但偶尔另一个线程会抢先一步,或比平常快一点,然后事情就会“轰隆”起来

当您引入带有断点的调试器时,您几乎可以保证带有断点的代码将在最后执行,因为您已经在执行过程中停止了它,而所有其他线程仍在运行

我建议您的列表的大小可能会随着您的执行而改变。当用户离开时,他们的条目是否会从“基本”列表中删除?在执行过程中,是否有其他情况可以从其他线程更改列表

我建议的第一件事是,将代码切换为使用迭代器,而不是直接的“for”循环。这不会使问题消失(实际上可能会使问题更加明显),但这将使发生的事情更加清楚。在修改发生时,您将得到ConcurrentModificationException,而不是只有在发生某些更改组合时才得到不太有用的NullPointerException。):

如果您在上面的代码中得到了并发修改异常,那么您肯定是在处理竞争条件。这意味着您必须同步代码

根据应用程序的结构,有几种方法可以做到这一点

假设竞争只发生在这段代码和另一段代码(从列表中删除的部分)之间,您可能可以通过将这两段代码包装在

synchronized(Start.bases)
{
   [your for-loop/item removal code goes here]
}
这将获得列表本身的锁,这样这两段代码就不会试图在不同线程中同时更新同一个列表。(请注意,它不会停止对基本对象本身的并发修改,但我怀疑这就是本例中的问题所在)

所有这些都表明,任何时候,当你有一个变量被多个线程读/写访问时,它确实应该被同步。那是一项相当复杂的工作。如果可以,最好将同步保持在您正在管理的对象内。这样,您可以在一个位置查看所有同步代码,从而减少意外创建死锁的可能性。(在上面的代码中,您需要将“for”循环与使用该列表的任何其他方法一起设置为Start类中的一个方法,然后将“base”设置为私有,以便应用程序的其余部分必须使用这些方法)


如果没有看到代码中访问此列表的所有其他位置,我无法确切说明应该进行哪些更改,但希望这足以让您开始。请记住,Java中的多线程需要一只非常精细的手

你能给我们看一下
base
的定义吗?你能给我们看一下错误的堆栈跟踪吗?由
getId()
返回的
id
字段的确切类型是什么?
Base
可能包含一个
null
值吗?这可能不会解决您的问题,但您应该像(Base-Base:Start.Base)那样迭代Start.Base,然后将
Start.Base.get(j)
作为
Base
处理。如果基础集合正在更改,则更干净,更不容易出现争用情况。请向我们显示确切的错误消息和堆栈traceNo,“j”的值不大于集合的大小-1。@146s,然后将代码的笔划分成几段,以确定出现分词表达式异常的位置。ConcurrentModificationException@146percentRussian,上面提到了一些东西-几个线程同时改变了您的集合。将所有读/写操作放在syncronized块中,或使用线程保存集合,如concurrentHashMap或HashTable。将所有调用放在如下块中:synchronized(Start.bases){Start.bases.add(…)}或synchronized(Start.bases){Start.bases.get(…)}。但这不是最好的解决方案。是的!添加同步后,我的服务器开始正常工作!!非常感谢你
 public class Base {
private ServerThread st;
private int id;
private String name;
private ArrayList<String> messages;

public Base(String n, ServerThread s_t, int i_d){
    messages = new ArrayList<String>();
    st = s_t;
    name = n;
    id = i_d;
}

public String getName(){
    return name;
}
public int getId(){
    return id;
}
public ServerThread getThr(){
    return st;
}
public String getMessage(){
    String ret = "";

    if(!messages.isEmpty()){
        ret = messages.get(0);
        messages.remove(messages.get(0));
    }

    return ret;
}

public void addMessage(String m){
    messages.add(m);
}

public boolean ifEmpty(){
    return messages.isEmpty();
}
  }
1) bases is null - you said its wrong
2) bases.get(j) - it may occur only if you collection size was reduced during iteration(as mentioned Gray)
3) Start.bases.get(j).getId() is null. But as you mentioned getId() method return primitive int, so its not the case as in this situation you receive null ponter while casting - in line "    return id;".
        for(Base currentBase : Start.bases)
        {
            if(currentBase.getId() == id && !currentBase.ifEmpty())
            {
                String output = currentBase.getMessage();
                os.println(output);
                System.out.println(output +" *FOT* "+ addr.getHostName());
            }
        }
synchronized(Start.bases)
{
   [your for-loop/item removal code goes here]
}