Java 多个线程将对象引用传递给静态帮助器方法

Java 多个线程将对象引用传递给静态帮助器方法,java,multithreading,methods,static,Java,Multithreading,Methods,Static,我只是Java的初学者,偶然发现了多线程应用程序。我知道这个问题类似于这里的一些帖子,但我找不到更好的答案来回答我的问题。基本上,我想将一个对象传递给一个静态方法,该方法将根据对象的值/属性返回一个输出。对于每次调用,我都会创建一个新的对象实例,并且我不会以任何方式修改方法中的对象。现在,我的问题是,JVM是否会为多个线程的每次调用在堆栈中创建静态方法的新实例及其局部变量(不包括堆上的对象)?为了清楚地了解我想要实现的目标,以下是我的代码: TestConcurrent.java import

我只是Java的初学者,偶然发现了多线程应用程序。我知道这个问题类似于这里的一些帖子,但我找不到更好的答案来回答我的问题。基本上,我想将一个对象传递给一个静态方法,该方法将根据对象的值/属性返回一个输出。对于每次调用,我都会创建一个新的对象实例,并且我不会以任何方式修改方法中的对象。现在,我的问题是,JVM是否会为多个线程的每次调用在堆栈中创建静态方法的新实例及其局部变量(不包括堆上的对象)?为了清楚地了解我想要实现的目标,以下是我的代码:

TestConcurrent.java

import classes.Player;

public class TestConcurrent
{
    private static int method(Player player)
    {
        int y = (player.getPoints() * 10) + 1;

            try {
                    Thread.sleep(1000);
            } catch (InterruptedException e) {}

            return ++y;
    }

    public static void main(String[] args) throws Exception
    {
        // Create 100 threads
        for(int i=1;i<=100;i++)
        {
            final int j = i;
            // Create a new Thread
            new Thread()
            {
                public void run()
                {
                    // Create a new instance of the Player class
                    Player player = new Player(j,j,"FirstName" + j, "LastName" + j);
                    // Call static method() and pass a new instance of Player class
                    System.out.println("Thread " + j + ": " + TestConcurrent.method(player));
                    // Check the values of the Player class after the call to the static method()
                    System.out.println("Player" + player.getAcctId() + " : Points=" + player.getPoints() + " Name=" + player.getFirstName() + " " + player.getLastName());
                }
            }.start();
        }
    }

}
package classes;

public class Player
{
    private int acctId, points;
    String firstName, lastName;

    public Player(int acctId, int points, String firstName, String lastName)
    {
        this.acctId = acctId;
        this.points = points;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public int getAcctId() {
        return acctId;
    }
    public void setAcctId(int acctId) {
        this.acctId = acctId;
    }
    public int getPoints() {
        return points;
    }
    public void setPoints(int points) {
        this.points = points;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}
输出:

由于我没有放置synchronized关键字,因此每次输出都会不同,看起来类似于以下内容:(输出是正确的,这正是我所期望的,我只想澄清一下,我走的是正确的道路,因为我不想使用同步,因为它会减慢进程,因为每个线程都必须等待另一个线程完成,然后才能调用静态方法)

JVM是否会为多个线程的每次调用在堆栈中创建静态方法的新实例及其局部变量(不包括堆上的对象)

是的,完全正确

如果一个静态方法只引用局部变量,那么它是自动线程安全的(事实上,这也适用于非静态方法)


一般来说,如果可能的话,我会说你应该避免
静态的
。一般来说,由于静态成员在某种意义上是全局的,这使得代码更难测试和推理。
静态的
方法不是问题,只有
静态的
变量会在线程之间共享

所以两个线程调用

public static int sum(int a, int b) {
  int tmp = a + b;
  return tmp;
}
不会遇到问题

static int tmp;

public static int sum(int a, int b) {
  tmp = a + b;
  return tmp;
}
多线程将失败,因为一个线程可能会覆盖另一个线程的
tmp

即使在
静态
方法中,局部变量仍然是局部的,因此是安全的


使用
静态
方法很好。它强调了该方法不需要访问对象变量。使用
静态
非常量变量容易出错,请不惜一切代价避免这种情况(如果需要访问变量,请对常量使用同步).

+1-第一个问题很好!欢迎使用StackOverflow!
静态
方法非常好而且使用合理。例如
Math.min
。常量如
Math.PI
。只有避免非最终的
静态
变量,它们会导致各种多线程错误。感谢您的快速响应。这这就是我想要实现的。我希望helper方法像一个全局方法一样,任何线程都可以随时调用。我最初的设计实际上是该方法在一个普通类中,然后每个线程将创建一个类的实例,然后调用该方法。我实际的静态方法内部有很多逻辑,我很担心每次我创建一个新的实例时,我都会考虑性能。但是正如我上面演示的,该方法不会修改传递给它的对象。如果我继续使用静态方法,会更好吗?@PopoyMakisig,这是一个很难回答的问题。我曾经用一个相当核心的类
Server
编写了一个游戏,我不得不这样做我厌倦了创建静态方法。起初它看起来非常简单,但最后我后悔了这个决定,并恢复了。如果我是你,我会尝试一下,看看它是如何工作的。如果它能起作用,我会很高兴,如果你最终改为丁:-)@Anony Mouse,在大多数情况下,我倾向于同意你的观点。然而,静态方法并不是一种非常面向对象的编程方式。我可以在像
数学
这样的课程中看到它的用途,但在我看来这是非常罕见的情况。另一个缺点是为测试目的模拟方法的问题。如果它们不是静态的,这就容易多了。在我的应用程序中,我不打算使用任何静态的非常量变量。如果需要定义常量,我只使用最终静态变量。所以现在一切都很顺利。当我已经非常清楚Java的并发特性时,我将使用同步和/或实例方法。谢谢你的回答。你刚刚用这句话救了我的命:“局部变量,即使在静态方法中,仍然是局部的,因此是安全的。”我对这个答案感到惊讶。直觉上这是错误的,但谢天谢地,事实并非如此!当一个人使用过编译器时,这应该是相当明显的。局部变量存储在“堆栈”上;由于每个线程都必须有自己的堆栈,因此它们无法看到彼此的局部变量。事实上,它们的地址是相对于当前堆栈指针的,因此在同一堆栈上也可能有多个副本。否则,递归也无法正常工作。
static int tmp;

public static int sum(int a, int b) {
  tmp = a + b;
  return tmp;
}