Java Locks同步烘焙传输方法

时间:2012-03-06 15:41:38

标签: java multithreading synchronization locks

您好我有一个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。

作为最后的贡献,我会请你仔细检查同步是否正确完成,因为我不是多线程的专家。再次感谢,并抱歉今天早上严厉提出问题......

2 个答案:

答案 0 :(得分:3)

修改

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

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

所以最有可能brnull。你应该在那里放一个断点并调试它以查看它们是否存在。您还可以使用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(); }

答案 1 :(得分:1)

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

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

我认为您从run()显示的行包含第27行。如果没有,请发布run()的完整源代码。