【问题标题】:Java Locks synchronize methods baking transfer [closed]Java锁同步方法烘焙传输[关闭]
【发布时间】:2012-03-06 15:41:37
【问题描述】:

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

你觉得同步好吗?

有什么建议吗?非常感谢


更新(我无法回答自己)

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

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

【问题讨论】:

  • Operation:27 是哪一行?那条线上什么可以为空?
  • 查看 Operation.java 类的第 27 行并调试当时哪个变量是 null。我们看不到它,所以我们不知道问题出在哪里。
  • 第27行是“b.transfer(id,r.nextInt(max),r.nextInt(100));”
  • 所以很可能br 为空。 idmax 也可能导致 NPE,如果其中一个是 Integernull 并自动装箱。
  • r 为空,因为我删除了 r 的初始化,现在应该没问题,但“数组越界”错误仍然存​​在....

标签: java multithreading synchronization locks


【解决方案1】:

编辑:

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

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

所以br 最有可能是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(); }

【讨论】:

  • 那将是一个错误的加入数字,但这会抛出一个索引超出范围异常,因为他在数组中没有那么多线程。
  • 好点@Lirik。我没有看到代码顶部的初始化。谢谢。
  • 其实我都没注意到初始化,所以现在唯一能发生的就是他只能在线程数小于100的时候得到一个index out of range的异常。
  • 好的,谢谢,100 实际上是之前测试的错误,但我仍然有问题。我现在将使用新代码更新我的问题...
【解决方案2】:

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

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

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

【讨论】:

  • 请注意,这不会解决您的问题;它只是为了帮助您找出哪些实例变量为空,以便您可以做一些事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-18
  • 2022-01-26
  • 1970-01-01
  • 1970-01-01
  • 2011-12-24
  • 2017-03-07
  • 1970-01-01
相关资源
最近更新 更多