当多个线程在Java中访问相同的方法时,线程安全

时间:2018-03-26 12:13:33

标签: java multithreading

我有这样的方法

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

    store(key, data);
}

如果多个线程同时调用此方法,那么数据的值是否会在多个线程之间共享?

如果线程A通过handleString(objFromThreadA)调用此方法,则线程B通过handleString(objFromThreadB)调用此方法。是否有可能线程A中String data的值被线程B中的String data值替换?

-----编辑1 -----

我对这里的线程安全感到有些困惑。下面的方法是从我用于MQTT客户端的lib回调。

/**
     * 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;

每次调用此方法时。我创建了一个新线程来处理message对象,这是我从message对象获取大量数据和密钥。当我阅读评论时,它说这个方法是同步调用的,那么这意味着消息肯定是线程安全的吗?

这是我处理邮件对象的方式。

@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);
}

在handleMessage(String topic,String message)中我有这样的东西:

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

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

所以,我不确定我在这里做的是否是线程安全的。如果我将一个新分配的String(new String(message.getPayload()))传递给我的handleMessage方法,这是否意味着新的String被放置在一个线程的堆栈上,没有其他线程可以共享该字符串?

1 个答案:

答案 0 :(得分:2)

每个方法调用都是自己范围内的方法。

您不需要线程使其可见 - 只需使用递归方法,以明确这一点:

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

在第4行中,调用了该方法的新实例,s现在是外部s的截断版本。但是在完成内部调用后,外部s根本不受影响。

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

对于线程,可能的碰撞(更好:不可能的碰撞)更难显示。

但问题是合法的。看看,乍一看,等效代码如何在bash中表现(对我而言,非常令人惊讶):

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 >