1

I have a method like this

private handleObj(Obj obj)
{
    String data = obj.getData;
    String key = obj.getKey;

    store(key, data);
}

If this method is called by multiple threads at the same time, will the value of data be shared across multiple threads?

Like if thread A calls this method by handleString(objFromThreadA) then thread B calls this method by handleString(objFromThreadB). Would there be any chance that value of String data in thread A was replaced by value of String data in thread B?

----- Edit 1 -----

I am a bit confused about thread safety here. The method below is a callback from a lib that I am using for MQTT client.

/**
     * This method is called when a message arrives from the server.
     *
     * <p>
     * This method is invoked synchronously by the MQTT client. An
     * acknowledgment is not sent back to the server until this
     * method returns cleanly.</p>
     * <p>
     * If an implementation of this method throws an <code>Exception</code>, then the
     * client will be shut down.  When the client is next re-connected, any QoS
     * 1 or 2 messages will be redelivered by the server.</p>
     * <p>
     * Any additional messages which arrive while an
     * implementation of this method is running, will build up in memory, and
     * will then back up on the network.</p>
     * <p>
     * If an application needs to persist data, then it
     * should ensure the data is persisted prior to returning from this method, as
     * after returning from this method, the message is considered to have been
     * delivered, and will not be reproducible.</p>
     * <p>
     * It is possible to send a new message within an implementation of this callback
     * (for example, a response to this message), but the implementation must not
     * disconnect the client, as it will be impossible to send an acknowledgment for
     * the message being processed, and a deadlock will occur.</p>
     *
     * @param topic name of the topic on the message was published to
     * @param message the actual message.
     * @throws Exception if a terminal error has occurred, and the client should be
     * shut down.
     */
    public void messageArrived(String topic, MqttMessage message) throws Exception;

Every time this method is called. I create a new thread to handle the message object, which is I am getting a lot of data and keys from message object. As I read the comments, it says that this method is called synchronously, so does that mean message is sure to be thread safe?

Here's how I handle the message object.

@Override
public void messageArrived(String topic, MqttMessage message) throws Exception
{
    Runnable runnable = new Runnable() 
    {   
        @Override
        public void run() 
        {
            try 
            {
                handleMessage(topic, new String(message.getPayload()));
            } 

            catch (Exception e) 
            {
                e.printStackTrace();
            }
        }
    };

    threadPool.execute(runnable);
}

And within handleMessage(String topic, String message) I have something like this:

private void handleMessage(String topic, String message)
{
    JSONObject messageJson = new JSONObject(message);

    //get values from JSON
    String value = messageJson.get("key");
}

So, I am not sure if what I am doing here is thread safe. If I am passing a newly allocated String (new String(message.getPayload())) to my handleMessage method, does that mean the new String is placed on stack of one thread, and no other threads can share that string?

JLT
  • 3,052
  • 9
  • 39
  • 86
  • That depends if the data and key are mutable and if store is thread-safe. Edit: I miss-read the question, I thought you asked if the function was thread-safe. – Neijwiert Mar 26 '18 at 12:15
  • 1
    No, those are local variables. Other threads don't affect them - but if multiple threads were reading/changing from the same `Obj` object at the same time, *that* could cause problems. (I haven't added an answer as I'm sure this is a dupe, but I don't have time to find it now.) – Jon Skeet Mar 26 '18 at 12:15
  • 1
    @Neijwiert: No, it really doesn't. The value of the `data` local variable in one thread will not be affected by another thread. – Jon Skeet Mar 26 '18 at 12:15
  • @JonSkeet I edited my comment, I miss-read the question. – Neijwiert Mar 26 '18 at 12:16
  • 2
    Threads can't exchange their values so, unless the `store` method is really a mess and coded awfully, there's no risk. Anyway i believe the `store` method has to be thread-safe at least. – Julien Mar 26 '18 at 12:19
  • 1
    Which method is static (the listed method doesn't look very static)? – Flocke Mar 26 '18 at 12:19
  • 1
    What @Julien said. Judging by the name, `store` preserves the data in a datastore. `handleObj` is thread safe if and only if `store` is thread safe, and vice versa. – M. Prokhorov Mar 26 '18 at 12:30
  • @Flocke Hi, I edited the title. Thanks for the mention. – JLT Mar 26 '18 at 12:42
  • You can have a look at this. https://stackoverflow.com/questions/12825847/why-are-local-variables-thread-safe-in-java – xingbin Mar 26 '18 at 13:21
  • @JonSkeet Hi, thanks for the answer. I have edited my question and added some more details. Please help me understand this if you got the time. Thanks! – JLT Mar 26 '18 at 16:59
  • @Julien Hi thanks for your answer. I have edited my question and added some more details. Please help me understand this if you got the time. Thanks! – JLT Mar 26 '18 at 16:59
  • It doesn't matter whether strings are shared or not - they're immutable. But you really need to distinguish between variables and objects... I don't see any mutable state in your `handleMessage` method, but then it doesn't seem to be useful yet either. – Jon Skeet Mar 26 '18 at 17:39

1 Answers1

3

Every method invocation is a method in its own scope.

You don't need threads to make it visible - just use a recursive method, to make this clear:

void middle (String s) {
    println ("<" + s);
    if (s.length () > 2) 
        middle (s.substring (1, s.length () - 1));
    println (s + ">");
}

In line 4, a new instance of the method is called, and s is now a truncated version of the outer s. But on completion of the inner call, the outer s is not affected at all.

-> middle ("foobar")
<foobar
<ooba
<ob
ob>
ooba>
foobar>

With threads, the possible collision (better: impossible collision) is only harder to show.

But the question is legitim. See, how, at first glance, equivalent code, behaves in bash (for me, very surprisingly):

middle () {
  s=$1
  echo "< $s"
  len=${#s}
  if (( $len > 2 ))
  then
      middle ${s:1:((len-2))}
  fi
  echo "$s >"
}

middle "foobar"

< foobar
< ooba
< ob
ob >
ob >
ob >
user unknown
  • 35,537
  • 11
  • 75
  • 121
  • +1 Very precise explanation of threads and good example. In addition to the question of @finalstatic, as he's confused by `new String()` I would just add : never instanciate a String unless you know for sure you need to, it could look easier to you to understand. [Here](https://stackoverflow.com/questions/2009228/strings-are-objects-in-java-so-why-dont-we-use-new-to-create-them) is a good explanation why. – Julien Mar 27 '18 at 07:42