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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18547476/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 08:56:35  来源:igfitidea点击:

how multiple threads invoke singleton object's method and work on them?

javamultithreading

提问by beinghuman

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
    }

}

采纳答案by Xtreme Biker

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

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

In a Singleton Objectyou have:

单例对象中,您有:

  • 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.

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

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 statelessmeans you've no fields into the singleton to be shared amongst them!

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

A word on Stateless and Stateful

关于无状态和有状态的一个词

Statelessmeans 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 sumoperation:

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

public class StatelessClass{

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

}

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

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

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 Singletonobject 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 sumcan be accessed by multiple threads at the same time, you should guarantee that totalSumis 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 Threadsafetypieceby @BalusC.

所有这一切都还正常在解释这个答案的Threadsafety一块由@BalusC。

回答by Yury Schkatula

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.

在这里,cafe是单例,pizza boy是CPU核,你和其他客户是线程,orders和pizza分别是输入和输出数据,table是一块内存。

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 可以区分您的数据并且不会混淆。当您询问堆栈时,它在这里不是一个重要的参与者,因为每个线程都有自己的堆栈(作为内存块的一部分)。

回答by Narendra Pathai

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

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

Why is it Thread Safe?

为什么它是线程安全的?

Thread Stacks are private to themand 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 obeing passed is itself thread safe or not. But as far as safety of Singleton is concerned it is thread safe.

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

回答by Niraj

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;

    public class MainClass {
        public final static int MAX_THREAD = 20;
        public MainClass() {
            // TODO Auto-generated constructor stub
        }

        public static void main(String[] args) {

            List<Singleton> singletonList = new MainClass().createSingletonObjects();
            singletonList = Collections.synchronizedList(singletonList); 

            int index = 0;
            for (int i = 0; i < MAX_THREAD; i++) {

                Thread thread1 = new Thread(new MyThread(singletonList,index), "Thread"+i);
                thread1.start();
                index++;
            if (index == singletonList.size()) {
            index = 0;  
            }

            }

        }

    public synchronized List<Singleton> createSingletonObjects(){
        List<Singleton> listSingleton = new ArrayList<Singleton>();
            listSingleton.add(MySingleton1.getInstance());
            listSingleton.add(MySingleton2.getInstance());
            listSingleton.add(MySingleton3.getInstance());
            listSingleton.add(MySingleton4.getInstance());
            listSingleton.add(MySingleton5.getInstance());

            return listSingleton;

        }

    }


public class MySingleton1 extends Singleton{
    private static Singleton mySingleton;
    private MySingleton1() {
        super();
        // TODO Auto-generated constructor stub
    }

    public static Singleton getInstance() {
        if (mySingleton == null) {
            mySingleton = new MySingleton1();
            return mySingleton;
        }
        return mySingleton;
    }


public class MySingleton2 extends Singleton{
    private static Singleton mySingleton;
    private MySingleton2() {
        super();
        // TODO Auto-generated constructor stub
    }

    public static Singleton getInstance() {
        if (mySingleton == null) {
            mySingleton = new MySingleton2();
            return mySingleton;
        }
        return mySingleton;
    }







}


public class MySingleton3 extends Singleton{
    private static Singleton mySingleton;
    private MySingleton3() {
        super();
        // TODO Auto-generated constructor stub
    }

    public static Singleton getInstance() {
        if (mySingleton == null) {
            mySingleton = new MySingleton3();
            return mySingleton;
        }
        return mySingleton;
    }







}


public class MySingleton4 extends Singleton{
    private static Singleton mySingleton;
    private MySingleton4() {
        super();
        // TODO Auto-generated constructor stub
    }

    public static Singleton getInstance() {
        if (mySingleton == null) {
            mySingleton = new MySingleton4();
            return mySingleton;
        }
        return mySingleton;
    }







}


public class MySingleton5 extends Singleton{
    private static Singleton mySingleton;
    private MySingleton5() {
        super();
        // TODO Auto-generated constructor stub
    }

    public static Singleton getInstance() {
        if (mySingleton == null) {
            mySingleton = new MySingleton5();
            return mySingleton;
        }
        return mySingleton;
    }







}