java - 多个线程如何调用单例对象的方法并对其进行处理?

标签 java multithreading

我有多个线程正在运行,它们访问单例对象并调用其方法并在其中传递对象。在该方法中,我只对收到的对象进行一些计算。 我听说在这种情况下不会有任何问题,因为它是无状态的,而且对所有人都是免费的。

我的问题是它如何对所有人免费? 我想知道多个线程如何在自己的线程中调用共享方法而不覆盖其他线程传递的对象? 请在内存分配方面和堆栈级别进行解释。

class Singleton class{

    //no shared class or object variables and only one copy of this Singleton object exists.

    Object someMethod(Object o){
        //do some calculation or logic on the object o and return some string result
    }

}

最佳答案

我认为你必须区分你已经存储在内存中的内容和代码执行。

单例对象中你有:

  • 字段:它们存储在内存中。它们可以在多个线程之间共享,您无法保证它们会保持一致(除非您使它们同步)。
  • 要调用的方法:可以从多个线程调用它们。每次执行都是独立且线程安全的,除非它们不正确地访问了某些共享字段。

现在来回答您的问题:如果您在多个线程之间共享单例对象并同时访问它,则每个线程都将执行单例对象的代码部分,并包含在自己的执行中。

另外,如果你写一个 Thread.currentThread().getId(); 基本上返回你正在执行的单例方法的线程 ID,你将获得不同的 id,因为不同的线程正在执行他们自己的方法堆栈。成为 无状态 意味着您在单例中没有可在它们之间共享的字段!

关于无状态和有状态的一句话

Stateless 意味着 bean 没有任何可修改的字段可以共享。这意味着您的对象中只有方法或/和静态内容,因此您可以在任何地方使用它们并且始终返回相同的结果。您不必担心同步对字段的访问。

这是一个关于 stateless 的基本示例,假设您有一个只执行 sum 操作的类:

public class StatelessClass{

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

}

同样,您可以将其声明为 abstract 类(本身不能实例化)并使其方法 static,这意味着您不需要任何实例调用它的方法:

public abstract class StatelessClass{

    /**
    *   I only sum objects
    */
    public static int sum(int a, int b){
        return a+b;
    }

}

然后你可以把它当成StatelessClass.sum(1,1);,这实际上和拥有一个Singleton对象本身非常相似,不同之处在于在 Singleton 中,您有一个在应用程序中共享的唯一实例。

以同样的方式,拥有一个被注入(inject)并提供对服务的访问的字段都不会被认为会改变对象的状态:

public class StatelessServiceClass{

    private Service service;

    public int sum(int a, int b){
        return service.sum(a,b);
    }

    public void setService(Service serv){
        this.service=serv;
    }

}

但是,具有可修改的字段会使对象有状态:

public class StatefulClass{

    //This fields make the object STATEFUL
    private int totalSum = 0;

    public int sum(int a, int b){
        int sum = a + b;
        totalSum = totalSum + sum;
        if (totalSum > 100)
            System.out.println("This thread "+Thread.currentThread().getId()+
                +" got it!");
        return sum;
    }

}

由于sum可以被多个线程同时访问,所以要保证totalSum是同步访问的。除非您这样做,否则不能保证打印的句子是真实的。

所有这些在 this answer's Threadsafety piece 中也得到了正确的解释。 @BalusC.

关于java - 多个线程如何调用单例对象的方法并对其进行处理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18547476/

相关文章:

java - Java 中带有 lambda 表达式的 forEach 方法是什么?

java - 单元测试具有外部依赖性的 apache beam 有状态管道

linux - C++11:Linux 上的 std::thread 是否依赖于 pthread 库?

Python 在线程中获取/发布数据

c# - 在 ContinueWith 中观察任务异常

android - 无法创建线程中的 WebView

java - 如何在MongoDB JAVA中向对象追加数据并在一页上显示其内容?

java - 在 freemarker 中切换枚举

java - 如何正确加密合并的pdf文档

java - 无法理解类对象