小编典典

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

java

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

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

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
    }

}

阅读 939

收藏
2020-12-03

共1个答案

小编典典

我认为您必须区分已经存储在内存和代码执行之间。

单例对象中, 您具有:

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

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

另外,如果编写的a
Thread.currentThread().getId();基本上返回正在执行的线程ID的单例方法,则将获得不同的id,因为不同的线程正在执行自己的方法堆栈。作为
无国籍 意味着你已经没有字段到单到他们之间可以共享!

关于无状态和有状态

无状态
意味着Bean没有可共享的字段。这意味着您的对象中仅包含方法或静态对象,因此您可以在任何地方使用它们,并且始终会返回相同的结果。您不必担心同步对字段的访问。

这是有关 无状态 的基本示例,假设您有一个仅执行 求和 运算的类:

public class StatelessClass{

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

}

以相同的方式,您可以将其声明为 抽象 类(本身不能实例化),并将其方法设为 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中,您有一个唯一实例在应用程序中共享。

以相同的方式,具有被注入并提供对服务的访问的字段都不认为会改变对象的状态:

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以同步方式进行访问。除非您这样做,否则不能保证印刷的句子为真。

2020-12-03