0
public Boolean performAction(AppleCollectorAgent agent, data.ActionType action)
{
    if(agent != null && action != null)
    {
        actions.put(agent, action);
    }
    else
    {
        System.out.println("GRID:  "+agent+" performs "+action+" TID: "+Thread.currentThread().getId()+". Time: "+ new Date().getTime());
        System.out.println("Either agent or action was null: "+agent+" - "+action);
    }
}

is called by

ActionType ac = ActionType.ApplePickup;
System.out.println("AGENT: "+myAgent+" going to perform "+ac+" TID: "+Thread.currentThread().getId()+". Time: "+ new Date().getTime());
success = GridWorld.get().performAction((AppleCollectorAgent)myAgent, ac);

This works fine for other values of the enum Action, but for the value Action.PickupApple, actions.put throws a NullPointerException. When I put some println's around to display the values for the arguments, it gets even weirder. Before the call, ac is printed as PickApple, and in performAction, action gets printed as null:

GRID:  Agents.GreedyAgent@1a42792 performs null TID: 29. Time: 1296317211796
Either agent or action was null: Agents.GreedyAgent@1a42792 - null
AGENT: Agents.GreedyAgent@1a42792 going to perform ApplePickup TID: 29. Time: 1296317211796

So, how can action become null in performAction?

Some explanation on the background: for a course on multi-agent systems, I have to make a simulation of a gridworld, in which agents can wander around and pick up apples. In each simulation step, each agent can perform one action. The actions types are stored in the enum data.Action. actions is a ConcurrentHashMap, in which each agent stores the Action he wants to do. When all agents have done that, the gridworld processes all that and reports back a Boolean, indicating the success of the action. Each agent has its own thread, as does the gridworld. Further down performAction() there are some syncing mechanisms. I first thought it would be the multithreading that went all wrong, but I think I can safely that that is not the problem. action is null, that is the problem.

Peter Coulton
  • 54,789
  • 12
  • 54
  • 72
Loy
  • 103
  • 11
  • What happens if you pass `Action.PickupApple` as the argument directly in the method call instead of `ac`? Does the `action` parameter still print as null? – Bert F Jan 29 '11 at 14:30
  • What should `data.Action` mean? According to std conventions, data is no type, so `data.Action` makes no sense. I'd clean it up before searching for weird things. Is `actions` a null-forbidding map? – maaartinus Jan 29 '11 at 14:43
  • @maaartinus `data` will be a package name. – Tom Hawtin - tackline Jan 29 '11 at 15:09
  • It's probably `myAgent` which is `null`. Or `actions`. My money is on some other mistake not contained in question. – Tom Hawtin - tackline Jan 29 '11 at 15:10
  • It's irrelevant, but why does performAction() returns a Boolean instead of boolean? As for the question, I am at loss. I'd do a clean & build, although it beats me why such thing could happen in the first place. References are passed by value in Java so performAction() wouldn't be able to change its argument even if it wanted to. – Sergei Tachenov Jan 29 '11 at 15:14
  • @Tom: Right, this is an explanation (although it goes against the conventions, too). – maaartinus Jan 29 '11 at 15:15
  • @Tom, that wouldn't explain why action gets printed as null in the performAction(). – Sergei Tachenov Jan 29 '11 at 15:16
  • Ive added some printlns, which show what is going on. the map actions is not null, agent is not null, but action is. After a few rebuilds, clean all that kind of stuff, makes no difference. I even put PickApple in a different place in the enum, which of course doesn't matter. – Loy Jan 29 '11 at 15:18
  • Did you try renaming it? Of course, it doesn't matter either, but when crazy things are happening, it's time for crazy solutions. Sometimes you find the right one by pure chance. – Sergei Tachenov Jan 29 '11 at 15:30
  • Tried renaming it, makes no difference. The funny thing is, the action does actually get performed, but not always. I'm at a loss here. Could it be anything with multithreading? – Loy Jan 29 '11 at 15:35
  • I can't possibly think of any situation where another thread could modify a local variable or an actual argument of some method. Not to mention altering an enum which is immutable by definition. Even if you use closures, they can only work with final variables so they can't change their values at all. The only possibility for multithreading is that another thread calls performAction() with null parameter. Try this: put your action in a variable (as it was in the first edition), then println() it along with the current thread id, then do the same thing inside performAction(). – Sergei Tachenov Jan 29 '11 at 15:46
  • Here comes areal kicker: ` GRID: Agents.GreedyAgent@b4e29b performs null TID: 29 Either agent or action was null: Agents.GreedyAgent@b4e29b - null AGENT: Agents.GreedyAgent@b4e29b going to perform ApplePickup TID: 29 ` The order is backwards! – Loy Jan 29 '11 at 15:53
  • I've added some timestamps. The number is exactly the same, but the order of printing is the reverse of what one would expect. Its freaking me out! – Loy Jan 29 '11 at 16:09
  • By the way, there are 4 agents, so, including the gridworld, there are 5 threads in total in play. Not that shocking, i'd say – Loy Jan 29 '11 at 16:12

1 Answers1

1

Deduced from the comments, I'd say that performAction is being called twice. Especially if it seems to "sometimes" work. Once with action as null, and once with action as PickApple.

If this is the case, you can use Thread.currentThread().getStackTrace() to work out from where the method is called.

waxwing
  • 18,547
  • 8
  • 66
  • 82
  • 1
    That was it. There was a whole different behaviour that also tried to performAction, with a null ActionType. You know that feeling that something has been bothering you for a whole day or more and it turns out to be really simple? I have that now... – Loy Jan 29 '11 at 16:22
  • So frustrating. Thanks for all the help, people – Loy Jan 29 '11 at 16:28