多个线程如何调用单例对象的方法并对它们起作用?

时间:2022-04-12 13:51:31

I have multiple threads running which access singleton object and call its method and pass objects in it. In the method I do some calculations only on recieved object. I have heard that there would not be any problem in this case cause it is stateless and it is free for all.

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

My question is how it is free for all? I want to know how multiple threads can call the shared method in their own thread without overwriting the passed objects of other threads? Please explain in terms of memory allocation wise and at stack level.

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

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
    }

}

3 个解决方案

#1


47  

I think you have to distinguish between what you've already stored in memory and code execution.

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

In a Singleton Object you have:

在Singleton对象中,您有:

  • Fields: They are stored in memory. They can be shared amongst multiple threads and you have no guarantee they will keep consistent (unless you make them synchronized).
  • 字段:它们存储在内存中。它们可以在多个线程之间共享,并且您无法保证它们将保持一致(除非您使它们同步)。

  • Methods to be called: They can be called from more than one thread. Each execution is independent and thread safe, unless they access some shared field improperly.
  • 要调用的方法:可以从多个线程调用它们。除非他们不正确地访问某些共享字段,否则每个执行都是独立且线程安全的。

Now coming to your question: if you share your singleton object among multiple threads and access it concurrently, every single thread will execute Singleton object's portion of code, wrapped in its own execution.

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

Also if you write a Thread.currentThread().getId(); which basically returns the thread ID you're executing into singleton's methods, you will obtain different ids, because different threads are executing their own method stack. Being stateless means you've no fields into the singleton to be shared amongst them!

如果你写一个Thread.currentThread()。getId();它基本上将您正在执行的线程ID返回到singleton的方法中,您将获得不同的ID,因为不同的线程正在执行自己的方法堆栈。无国籍意味着你在单身人士中没有任何领域可以在他们之间分享!

A word on Stateless and Stateful

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

Stateless means that the bean hasn't got any modifiable field to share. That means you have only methods or/and static stuff in your object, so you can use them anywhere and will always return you same result. You don't have to worry about synchronizing the access to the field.

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

That's a basic example about stateless, let's suppose you have a class that only performs the sum operation:

这是关于无状态的基本示例,假设您有一个只执行求和操作的类:

public class StatelessClass{

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

}

In the same way, you can declare it as a abstract class (no instantiable itself) and make its methods static, which means you don't need any instance of it to call its methods:

以同样的方式,您可以将它声明为抽象类(本身没有实例化)并使其方法为静态,这意味着您不需要任何实例来调用其方法:

public abstract class StatelessClass{

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

}

Then you can use it as StatelessClass.sum(1,1);, this actually would be very similar to have a Singleton object itself, with the difference that in the Singleton you have a unique instance shared in the application.

然后你可以将它用作StatelessClass.sum(1,1);,这实际上与拥有一个Singleton对象非常相似,区别在于在Singleton中你有一个在应用程序*享的唯一实例。

In the same way, having a field which is injected and provides access to a service neither is considered to alter the state of the object:

以同样的方式,使用注入的字段并提供对服务的访问也不会被视为改变对象的状态:

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

}

However, having a field which is modifiable makes the Object stateful:

但是,具有可修改的字段会使Object成为有状态:

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

}

As sum can be accessed by multiple threads at the same time, you should guarantee that totalSum is accessed in a synchronized way. The printed sentence is not guaranteed to be true unless you do it.

由于sum可以同时由多个线程访问,因此应保证以同步方式访问totalSum。除非你这样做,否则打印的句子不能保证是真实的。

All of this is also properly explained in this answer's Threadsafety piece by @BalusC.

所有这一切也在@BalusC的答案的Threadsafety中得到了恰当的解释。

#2


4  

You can think about it in "pizza terms". You went to pizza cafe, and couple of other guys entered with you as well. Each one placed his order and then sat to his own table. Pizza boxes to be arrived then and each of you start eating his own meal.

你可以用“披萨术语”来思考它。你去了披萨咖啡馆,其他几个人也和你一起去了。每个人都下了订单,然后坐在他自己的桌子旁。然后到达披萨盒,你们每个人都开始吃自己的饭。

Here, the cafe is a singleton, pizza boys are CPU cores, you and other customers are threads, orders and pizza are input and output data respectively, table is a piece of memory.

在这里,咖啡馆是单身人士,披萨男孩是CPU核心,你和其他客户都是线程,订单和披萨分别是输入和输出数据,表是一块内存。

As you can see, each thread is served with his own piece of memory so CPU can distinguish your data and don't mix up. As you asked about stack, it's not a significant player here because each thread has it's own stack (as a part of your memory chunk).

正如您所看到的,每个线程都有自己的内存,因此CPU可以区分您的数据并且不会混淆。当你问到堆栈时,它不是一个重要的参与者,因为每个线程都有它自己的堆栈(作为你的内存块的一部分)。

#3


4  

Every thread has its own copy of the Object o and so even if multiple threads call the method at the same time, each method call of Thread will have its own stack allocated and the logic will apply there.

每个线程都有自己的Object o副本,因此即使多个线程同时调用该方法,Thread的每个方法调用都会分配自己的堆栈,逻辑将在那里应用。

Why is it Thread Safe?

Thread Stacks are private to them and are by default thread safe as no other thread can enter in others stack.

线程堆栈对它们是私有的,并且默认情况下是线程安全的,因为没有其他线程可以进入其他堆栈。

NOTE: You can say that this Singleton of yours is Thread safe but not that the application is Thread safe as it also depends on whether the Object o being passed is itself thread safe or not. But as far as safety of Singleton is concerned it is thread safe.

注意:你可以说你的Singleton是线程安全但不是应用程序是线程安全的,因为它还取决于传递的Object o本身是否是线程安全的。但就Singleton的安全性而言,它是线程安全的。

#1


47  

I think you have to distinguish between what you've already stored in memory and code execution.

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

In a Singleton Object you have:

在Singleton对象中,您有:

  • Fields: They are stored in memory. They can be shared amongst multiple threads and you have no guarantee they will keep consistent (unless you make them synchronized).
  • 字段:它们存储在内存中。它们可以在多个线程之间共享,并且您无法保证它们将保持一致(除非您使它们同步)。

  • Methods to be called: They can be called from more than one thread. Each execution is independent and thread safe, unless they access some shared field improperly.
  • 要调用的方法:可以从多个线程调用它们。除非他们不正确地访问某些共享字段,否则每个执行都是独立且线程安全的。

Now coming to your question: if you share your singleton object among multiple threads and access it concurrently, every single thread will execute Singleton object's portion of code, wrapped in its own execution.

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

Also if you write a Thread.currentThread().getId(); which basically returns the thread ID you're executing into singleton's methods, you will obtain different ids, because different threads are executing their own method stack. Being stateless means you've no fields into the singleton to be shared amongst them!

如果你写一个Thread.currentThread()。getId();它基本上将您正在执行的线程ID返回到singleton的方法中,您将获得不同的ID,因为不同的线程正在执行自己的方法堆栈。无国籍意味着你在单身人士中没有任何领域可以在他们之间分享!

A word on Stateless and Stateful

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

Stateless means that the bean hasn't got any modifiable field to share. That means you have only methods or/and static stuff in your object, so you can use them anywhere and will always return you same result. You don't have to worry about synchronizing the access to the field.

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

That's a basic example about stateless, let's suppose you have a class that only performs the sum operation:

这是关于无状态的基本示例,假设您有一个只执行求和操作的类:

public class StatelessClass{

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

}

In the same way, you can declare it as a abstract class (no instantiable itself) and make its methods static, which means you don't need any instance of it to call its methods:

以同样的方式,您可以将它声明为抽象类(本身没有实例化)并使其方法为静态,这意味着您不需要任何实例来调用其方法:

public abstract class StatelessClass{

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

}

Then you can use it as StatelessClass.sum(1,1);, this actually would be very similar to have a Singleton object itself, with the difference that in the Singleton you have a unique instance shared in the application.

然后你可以将它用作StatelessClass.sum(1,1);,这实际上与拥有一个Singleton对象非常相似,区别在于在Singleton中你有一个在应用程序*享的唯一实例。

In the same way, having a field which is injected and provides access to a service neither is considered to alter the state of the object:

以同样的方式,使用注入的字段并提供对服务的访问也不会被视为改变对象的状态:

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

}

However, having a field which is modifiable makes the Object stateful:

但是,具有可修改的字段会使Object成为有状态:

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

}

As sum can be accessed by multiple threads at the same time, you should guarantee that totalSum is accessed in a synchronized way. The printed sentence is not guaranteed to be true unless you do it.

由于sum可以同时由多个线程访问,因此应保证以同步方式访问totalSum。除非你这样做,否则打印的句子不能保证是真实的。

All of this is also properly explained in this answer's Threadsafety piece by @BalusC.

所有这一切也在@BalusC的答案的Threadsafety中得到了恰当的解释。

#2


4  

You can think about it in "pizza terms". You went to pizza cafe, and couple of other guys entered with you as well. Each one placed his order and then sat to his own table. Pizza boxes to be arrived then and each of you start eating his own meal.

你可以用“披萨术语”来思考它。你去了披萨咖啡馆,其他几个人也和你一起去了。每个人都下了订单,然后坐在他自己的桌子旁。然后到达披萨盒,你们每个人都开始吃自己的饭。

Here, the cafe is a singleton, pizza boys are CPU cores, you and other customers are threads, orders and pizza are input and output data respectively, table is a piece of memory.

在这里,咖啡馆是单身人士,披萨男孩是CPU核心,你和其他客户都是线程,订单和披萨分别是输入和输出数据,表是一块内存。

As you can see, each thread is served with his own piece of memory so CPU can distinguish your data and don't mix up. As you asked about stack, it's not a significant player here because each thread has it's own stack (as a part of your memory chunk).

正如您所看到的,每个线程都有自己的内存,因此CPU可以区分您的数据并且不会混淆。当你问到堆栈时,它不是一个重要的参与者,因为每个线程都有它自己的堆栈(作为你的内存块的一部分)。

#3


4  

Every thread has its own copy of the Object o and so even if multiple threads call the method at the same time, each method call of Thread will have its own stack allocated and the logic will apply there.

每个线程都有自己的Object o副本,因此即使多个线程同时调用该方法,Thread的每个方法调用都会分配自己的堆栈,逻辑将在那里应用。

Why is it Thread Safe?

Thread Stacks are private to them and are by default thread safe as no other thread can enter in others stack.

线程堆栈对它们是私有的,并且默认情况下是线程安全的,因为没有其他线程可以进入其他堆栈。

NOTE: You can say that this Singleton of yours is Thread safe but not that the application is Thread safe as it also depends on whether the Object o being passed is itself thread safe or not. But as far as safety of Singleton is concerned it is thread safe.

注意:你可以说你的Singleton是线程安全但不是应用程序是线程安全的,因为它还取决于传递的Object o本身是否是线程安全的。但就Singleton的安全性而言,它是线程安全的。