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

时间:2013-08-31 11:07:03

标签: java multithreading

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

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

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
    }

}

4 个答案:

答案 0 :(得分:55)

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

单身对象中,你有:

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

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

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

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

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

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

public class StatelessClass{

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

}

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

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

}

但是,拥有一个可修改的字段会使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;
    }

}

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

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

答案 1 :(得分:5)

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

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

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

答案 2 :(得分:5)

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

为什么线程安全?

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

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

答案 3 :(得分:0)

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







}