你能在不同的线程上调用相同的方法吗?

Posted

技术标签:

【中文标题】你能在不同的线程上调用相同的方法吗?【英文标题】:Can you call the same method on different threads? 【发布时间】:2014-12-12 20:11:23 【问题描述】:

我知道真的是菜鸟问题,但我试图了解方法和线程如何作为业余程序员工作。我敢肯定这是我根本缺乏理解,但希望一些好人可以让我直截了当。

我想知道的是,如果您使用多个线程多次调用同一个方法,您是否会创建每个方法的沙盒版本,它们彼此独立运行,或者它们会相互干扰。例如,我在下面敲了一些非常简单的代码来试图说明我的意思。

因此,在示例中,我们有一个在单击按钮时调用的方法。它需要两个数字并将它们提供给第二个方法,该方法将它们相加并返回结果。这似乎是直截了当的。但是想象一下,我们想使用相同的方法进行另一次计算,但我们不想等待第一次计算完成。我们可以调用在单独的线程上添加数字的方法,这样它就不会阻塞 UI 线程。凉爽的。好的,但是如果我们这样做两次呢?还是三倍?

我想问的是,第一次调用“doSum”时,传入的数字是 10 和 20。代码在单独的线程上运行该方法,应该返回答案 30。第二次它被称为数字是 30 和 50,结果应该是 80。如果由于某种原因第一个线程中的计算仍在继续,当我第二次调用相同的方法时它会被覆盖吗? result1 是否有被返回为 80 或 140 的危险?

这对任何人都有意义吗?

public void onbuttonclicked(View v) 

int number1;
int number2;
int result1, result2, result3;


//first callculation --------------------------------------
number1 = 10;
number2 = 20;
    Thread t1 = new Thread(new Runnable() 
        public void run() 
        result1 = doSum(number1, number2);
            
    );
    t1.start();


//second callculation -----------------------------------
number1 = 30;
number2 = 50;
    Thread t2 = new Thread(new Runnable() 
        public void run() 
        result2 = doSum(number1, number2);
            
    );
    t2.start();

//third callculation -----------------------------------------
number1 = 60;
number2 = 80;
    Thread t3 = new Thread(new Runnable() 
        public void run() 
        result3 = doSum(number1, number2);
            
    );
    t3.start();





public static int doSum(int a, int b)

    int result = a + b;
    return result;

【问题讨论】:

变量 number1 、 number2 和 number3 应该是 final。你的代码编译了吗? 或将他们移入课堂 【参考方案1】:

您主要应该知道两件事。

    如果 2 个线程调用同一个方法,每个线程将有一个不同的 堆栈帧 用于该方法。因此,方法局部变量是线程安全的。对一个方法的局部变量所做的更改不会干扰其他线程的更改。

    当您的共享资源被两个线程修改时,您应该(通常)担心线程安全/干扰。

PS:您的doSum() 只进行很少的处理。一个智能 JVM 可能实际上内联该方法。

【讨论】:

谢谢您 - 完美的回答,非常感谢。 至于2,你也应该担心一个线程修改数字(本题中的gui线程),其他线程使用该数字。传递给 doSum() 的数字已经受制于竞争条件。 @minghua - 我认为他的代码不会编译。变量必须是final。他的代码中没有竞争条件。 你的意思是说,同一个方法不同线程有不同的栈,可以独立修改? @Subhajit - 只有 1 个 Java 堆栈。每个线程对其调用的每个方法都有一个不同的堆栈帧(以保持变量的状态)。【参考方案2】:

在这种情况下,doSum() 没有问题。它仅使用传递的参数和本地变量。所以,doSum() 有:

1) 代码。二进制指令代码是线程安全的,除非自我修改,(永远不要那样做!)。

2) 本地变量和参数。在大多数架构上,这意味着寄存器和堆栈存储。由于每个线程都有自己的寄存器集和堆栈,因此不会发生冲突。

【讨论】:

好的 - 这里似乎有一些争论。马丁 - 作为反馈最多的人,我猜我会和你一起去,你似乎同意 TheLostMind 先生(第一个答案)对吗?我在想一个场景,你可能会调用一个函数来 ping 几个 IP。显然响应时间可能会有所不同,但只要变量保持在本地,您就应该能够在不同线程上调用相同的方法来 ping 多个 IP,而不会相互干扰? @Regnodulous,只需在您的 t1 中调用 doSum() 之前添加 100 毫秒延迟。你会看到它是 30、80 还是 140。 @Regnodulous - 您发布的示例很好,但这并不意味着具有更大范围的其他功能不会出现问题。 ICMP ping 是这些功能之一。 ping 没有套接字上下文,因此,当多个线程发送 ping 并且 gnip 进入时,网络堆栈无法将 gnip 路由到原始线程。 谢谢马丁。感谢帮助。有没有什么方法可以同时 ping 多个 ip 而不会阻塞 ui 线程?【参考方案3】:

java 中的线程独立运行,即。取决于你如何配置。当线程出现时,结果总是变得不可预测,意味着你第一次尝试的结果,它不会进入第二次。

在您的情况下,onbuttonclicked() 将由主线程处理/运行,这将创建其他 3 个线程。它完全取决于 ThreadScheduler,哪个线程将首先运行。因为此操作发生得非常快,这意味着初始化过程可能(并非总是)结束。

所以在这里,第一个线程可能会得到 140 的结果。这是不可预测的。

希望对您有所帮助。

【讨论】:

【参考方案4】:

这些线程独立运行,因此结果应该是随机的,完全取决于它们的速度。这是典型的比赛条件情况。也许您应该阅读有关比赛条件的信息,这应该不难理解。

随机意味着您的 t1 可能在 number1=30 之后的点调用 doSum() 因此结果 1 应为 50。但这只是一个示例。

【讨论】:

doSum() 中没有种族。 当它们到达 doSum() 的调用点时,传入的参数将是随机的。这是三个线程和主线程之间的竞赛。

以上是关于你能在不同的线程上调用相同的方法吗?的主要内容,如果未能解决你的问题,请参考以下文章

你能在同一个提交的一个函数中有两个ajax调用吗?

你能在不调用 org.freedesktop.DBus.Properties.Get 的情况下检索 D-Bus 属性吗?

你能在一个Hibernate会话中拥有多个交易吗?

你能在类型数组上写扩展方法吗?

你能在kivy中获得设备的物理尺寸吗?

使用类型变量调用泛型方法[重复]