-1

您好,我有一个 Java 应用程序,它需要输入数量的操作来执行,并且它为每个操作运行不同的线程:

//create operations to execute
Thread t[] = new Thread [n_operations];

//we create a Bank with N accounts
Bank mybank = new Bank(N);

//execute a separate thread per operation
for (int i = 0; i < n_operations; i++) {
    int id = i;
    Operation o = new Operation(mybank, id);
    t[i]= new Thread (o);
    t[i].start();
}
for (int i=0;i<N;i++){
    try{
        t[i].join();
        }catch(Exception e){;}
}

现在我需要对账户进行并发转账,其中 Bank 类的定义如下:

public class Bank {

    private static        Account[] accounts;
    final  int      MAX_balance  = 100000;
    int         MAX_accounts = 0;

    /* Create accounts of a bank */
    public Bank (int N) {

        accounts = new Account[N];
        MAX_accounts = N;

        for (int i = 0; i < N; i++)

            accounts[i] = new Account (i, 1000);

    }
    public int getN(){
        return MAX_accounts;
    }

    public synchronized int transfer(int from, int to, int amount) {


            synchronized (accounts[from]){
          synchronized (accounts[to]){

          if (accounts[from].balance () < amount) {

              try{
              System.out.println("Error during transfer: Not enough Money");
              }
              catch(Exception err){ 
                  return 1;
              }              
         }

         accounts[from].sub(amount);
         accounts[to].add(amount);
        }
    }

    return 0;
    }
}

当程序执行操作时:

public class Operation implements Runnable {

    private Bank      b;
    int id;
    Random r;
    private final int  MAX_TRANSFERENCIAS = 1000;

        public Operation (Bank b, int id) {

            this.b = b;
            this.id = id;

    }

    public int syncronize(){
        return 1;       
    }

    public void run () { 


        r = new Random();
        if(b == null)
              throw new RuntimeException("b is null!");
            if(r == null)
              throw new RuntimeException("r is null!"); 
        int max = b.getN();
        //depend if there is a conflict or not

            b.transfer (id,r.nextInt(max),r.nextInt(100));

    }
}

我收到了一系列类似此消息的错误:

        at Bank.transfer(Bank.java:28)         /* which is "synchronized (accounts[from]){" */

        at Operation.run(Operation.java:33)    /* which is "b.transfer 
(id,r.nextInt(max),r.nextInt(100));" */

        at java.lang.Thread.run(Unknown Source)
    java.lang.ArrayIndexOutOfBoundsException: 4714

你觉得同步好吗?

有什么建议么?非常感谢


更新(我无法回答自己)

主循环中存在概念错误(对于 i..to n_operations),函数正在传递“int id = i;” 作为source_account的参数,而n_operation数大于数组的最大值,所以编译器合理地说:ArrayIndexOutOfBoundsException。

作为最后的贡献,我请您检查同步是否正确完成,因为我不是多线程专家。再次感谢,很抱歉今天早上提出的问题很糟糕......

4

2 回答 2

3

编辑:

现在我们知道以下行是 NPE 的来源:

b.transfer (id,r.nextInt(max),r.nextInt(100));

所以很可能bor ris null。您应该在那里放置一个断点并对其进行调试以查看它们是否存在。您还可以使用assert或记录来显示值。还请记住,如果其中一个是“即”并且被自动装箱,则它idmax可能导致 NPE 。Integernull


这不会导致您的 NPE,但请注意n_operations可能不是 == 100?您正在启动n_operations线程,但加入了 100 个线程:

for (int i=0;i<100;i++){
    try {
        t[i].join();
    } catch(Exception e){;}
}

在这些情况下,我总是使用数组的长度,因此分配的内容不会不匹配:

for (int i = 0; i < t.length; i++) {

此外,至少您应该始终记录或打印您的异常。捕获和丢弃异常通常意味着您隐藏了重要的调试信息。

    } catch(Exception e){ e.printStackTrace(); }
于 2012-03-06T15:44:29.013 回答
1

您在其中使用的变量之一run()为空,但哪一个?尝试将以下内容添加到开头Operation.run()

if(b == null)
  throw new RuntimeException("b is null!");
if(r == null)
  throw new RuntimeException("r is null!");

我假设您显示的行run()包括第 27 行。如果没有,请发布完整的源代码run()

于 2012-03-06T15:48:14.033 回答