-1

In Java what happens when a method is called when a previous call to the same method is still executing? Does it execute typically,i.e create a different stack frame,with the local variables also local to each method call(not share it's local variables),for the new call to the method. Are there things to note while doing this?

lanezalbryt
  • 41
  • 1
  • 5
  • In the same thread this is called recursion and each method call have its own stack frame/activation record. – davidbuzatto May 10 '22 at 02:47
  • 1
    Please add code to show what you mean. Your logic does not flow. Are you talking about calling a method in a `Thread? Are you talking about calling a method recursively? If I haven't missed anything code will run sequentially. That means once one piece of code is done, only then will another piece of code run. – SedJ601 May 10 '22 at 02:48
  • 1
    @Sedrick: The method is located in an android service. And gets called in the service anytime the service is started from an activity. So yeah,it's much like calling a method in a thread. – lanezalbryt May 10 '22 at 03:21
  • Please provide enough code so others can better understand or reproduce the problem. – Community May 10 '22 at 07:49

1 Answers1

2

Java has 'local' variables, parameters (which are almost entirely identical to locals), and 'fields'.

All local variables exist on stack.

That means all java methods are inherently reentrant (you can call them from themselves, i.e. recursion - and each method has its own set of local vars, they aren't "reused", you don't overwrite any variables from the still-on-stack recursion 'above' you), and all java methods are inherently multi-threading capable in the sense that you can invoke the same method on the same object from many different threads simultaneously, and each local var is its own copy, unique to that invocation.

However.

Java has 2 types of variables: Primitives and References. A Primitive is simply any variable of a primitive type, and there are only 8 hardcoded primitive types: long, int, short, byte, float, double, char, and boolean. All primitives variables represent their actual value. For example, given:

void foo(boolean x) {
  int y = 5;
}

The stack frame when you're in the middle of that method contains 1 boolean value (generally just represented by a whole word's worth of bits, modern CPU architecture kinda dictates you do it that way), and 1 int value. If you were to call, say, foo(x, 10) in that method, and let's say x was true, then the stack would contain true, 5, true, 10. Java is pass-by-value, always.

But references are, in C terms, just pointers. They are one 'word' in size effectively, and it's a number that the JVM can use to look up an object.

All objects live on the heap, meaning, there's just the one copy unless you explicitly make clones or more objects. . dereferences the reference and will get you to the object on heap. Only objects have fields, and thus, all fields live on heap, too.

Hence:

void test() {
  List<String> x = new ArrayList<String>();
  x.add("Hello");
  foo(x);
  System.out.println(x); // THIS LINE WILL PRINT...
}

void foo(List<String> x) {
  x.add("World!"); // dereference pointer.
  x = new ArrayList<String>(); // Overwrite local var
  x.add("Goodbye");
}

This code will actually print [Hello, World]. The x in the foo method is a copy (because java is pass-by-value), and local - but it's 'pointing' at the same list that the xfrom the test method is. So, x. gets you to the same object, thus that call to .add("World!") is 'visible' from the test method. The foo method then overwrites its local by creating a new object (new, name kinda gives it away), and assigning the reference to it to the x variable, overwriting the local x, which has no effect at all on the x that test has, which still points at the old list.

The foo method than invokes a method on this new list, and then the method ends, with it, the x variables goes away (the stack frame is popped, and poof goes the reference), and thus that list that foo created is now inaccessible: It's an object and no references exist in any code that we can ever get to. That means it'll eventually be garbage collected by the JVM.

Java does not allow pointer math, you can't try to walk through the entire heap by just looping all memory addresses or some such. You can't do something like:

String x = *(someAddressInMemory);

In that sense, java pointers are very different from C pointers: "Pointer math" is simply not allowed; if you tried, the JVM class verifier would not let you. Hence, to avoid confusing, java uses the name 'reference' for the concept. It's the same thing as a pointer. Just, hopefully without the baggage.

That does mean that if you invoke the same method, and pass a reference to the same object, in multiple threads, they'll walk all over themselves and cause all sorts of trouble if they actually modify it. If you make 1 list, then in 5 threads you simultaneously call the same method 5 times, handing that one list to all of them, and that method calls, say, .add("Hello") on it, all heck breaks loose.

So don't do that.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72