我模仿网上的多线程不同写了一个自动提款机的小程序,一运行就扔空指针错误。我eclipse提示是Thread.start()方法错误了,可是我看不出这里怎么就空指针了,我明明创建了对象啊。public class my{
public static void main(String[] args){
ATM[] pArr=new ATM[100];
for(int i=0;i<pArr.length;++i){
pArr[i].start();
}
}
static class Account{
int m_amount;
String m_name;
Account(int m,String name){
m_amount=m;
m_name  =name;
}
void Deposit(int m){
try{
int a=m_amount;
a+=m;
Thread.sleep(100);
m_amount=a;
}catch(InterruptedException e){
e.printStackTrace();
}
}
void WithDraw(int m){
try{
int a=m_amount;
a-=m;
Thread.sleep(100);
m_amount=a;
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
static class ATM extends Thread{
static Account m_acc=new RevertList.Account(10,"self");
public void run(){
m_acc.Deposit(1);
m_acc.WithDraw(1);
}
}
}

解决方案 »

  1.   

    创建了数组,数组里的对象默认是null,需要初始化!
      

  2.   

    如果是基本类型的数组的话,系统会分配一个默认初始值,比如int数组就是0
    但如果是引用类型的话,分配了内存但没有初始化,即null,因而提示空指针异常
      

  3.   

    对象数组为空
    可以再for循环里创建多个线程
      

  4.   

    初学者常见错误:你只是创建了数组,但没有创建数组中的元素:
    for(int i=0;i<pArr.length;++i){
        pArr[i] = new ATM(); // 这才真的创建了数组中的元素所引用的对象。
        pArr[i].start();
    }
      

  5.   

    ATM[] pArr=new ATM[100];
    你只是创建了数组,但没有创建数组中的元素所以是个长度为100的空数组
      

  6.   

    ATM[] pArr=new ATM[]{new ATM()};
      

  7.   


    这种写法不能指定数组的大小啊:
    ATM[] pArr=new ATM[100]{new ATM()};//编译器会报错。如何又能指定大小,又能在创建数组的时候指定new ATM()呢?
      

  8.   


    我理解了,Java里面数组本身是个对象,它包含了若干个对象的引用,这些引用本身还得创建为实际对象,这是和C++不同的地方。 
      
    OK,我在创建了数组以后加上了创建Thread对象的语句。不过虽然我的Deposit和Withdraw方法都是没有加synchronized锁的,但是看起来我程序运行若干次的结果,最后的amount都是正确的。网上说的多线程导致amount发生错误的情况并没有发生啊。难道我的程序设计的问题吗? 很疑惑。 
      
    还请各位高手继续指教 !
    public class my{
    public static void main(String[] args){
    ATM[] pArr=new ATM[100]{new ATM()};
    for(int i=0;i<pArr.length;++i){
    //pArr[i]=new ATM();
    pArr[i].start();
    }
    System.out.println("Final amount="+ATM.m_acc.m_amount);
    }
    static class Account{
    int m_amount;
    String m_name;
    Account(int m,String name){
    m_amount=m;
    m_name  =name;
    }
    void Deposit(int m){
    try{
    int a=m_amount;
    a+=m;
    Thread.sleep(100);
    m_amount=a;
    }catch(InterruptedException e){
    e.printStackTrace();
    }
    }
    void WithDraw(int m){
    try{
    int a=m_amount;
    a-=m;
    Thread.sleep(100);
    m_amount=a;
    }catch(InterruptedException e){
    e.printStackTrace();
    }
    }
    }
    static class ATM extends Thread{
    static Account m_acc=new RevertList.Account(10,"self");
    public void run(){
    m_acc.Deposit(1);
    m_acc.WithDraw(1);
    }
    }
    }
      

  9.   


    我按照你的说法来做了,不过发现,每次运行的结果都是"正确的"。这很奇怪,按照网上的说法,这个程序我既然没有对Deposit和Withdraw来加锁,那么应该运行的结果不确定才对啊。
      

  10.   

    我想是因为sleep时间有些长,错误不明显,lz可以减小sleep时间
    有耐心的等待结果
      

  11.   

    正解,未初始化的数组,是不能直接引用的,楼主下次要注意了,再者,这些东西,看看异常分析,看不懂的就baidu,解决问题会快很多
      

  12.   

    与其在这里告诉LZ是什么引起了空指针异常,还不如告诉LZ怎么用Debug调试。你这次知道原因了,下次一粗心,不会又来这里发个帖子吧。
    Debug断点到发生错误的地方,然后看变量,(x)=Variables窗口你调试的时候看过多少次?出了问题就一头裁进代码里看,睁大了眼睛,自信满满的以为看一眼就能知道哪里出错,总有一天你会感觉到头昏脑胀的。
      

  13.   

    关于第10楼----
    难道你认为'Final amount=10'的结果是正确的? 它可以是这样的情况
    1. 所有ATM的线程都还没跑到run里面(毕竟需要时间),就输出了
    2. 所有ATM的线程都还没跑到给m_amount赋值那里,就输出了
    3. 有一个ATM的线程'刚好'跑完一个run而其它线程处于1 或 2的情况,就输出了.
    ---
    要重现错误,只要在Debug下控制不同线程在run里一步一步跑上去就很容易看到了.
      

  14.   

    ATM[] pArr=new ATM[100];
            for(int i=0;i<pArr.length;++i){
                pArr[i].start();
            }
    你只定义了一个叫pArr的数组,其长度为100,但并未初始化