Java单例模式 - 更新实例化变量

时间:2015-09-26 15:55:49

标签: java design-patterns singleton

想要了解一下单身人士模式。

如果我实现如下所示的单例模式,我可以做什么,以便其他类可以更新并查看someString和someInt字段的更新?

从我读到的关于Singleton模式的内容来看,不变性不是先决条件之一。从技术上讲,我可以为字段设置setter方法并更改它们,并将这些更改显示给其他类吗?例如,如果我有另外两个类实现Runnable并且每隔几秒打印一次Foo字段。我试过这个,发生了什么事情,每个班级只看到自己的更新而没有其他班级。#/ p>

public class Foo {
    private static Foo instance;
    private String someString;
    private int someNum;

    private Foo(){
        someString = "a";
        someNum = 1;
    }

    public static Foo getInstance(){
        if(instance == null){
            instance = new Foo();
        }
        return instance;
    }

    public void setSomeString(String someString) {
        this.someString = someString;
    }

    public void setSomeNum(int someNum) {
        this.someNum = someNum;
    }

    @Override
    public String toString() {
        return "Foo{" +
                "someString='" + someString + '\'' +
                ", someNum=" + someNum +
                '}';
    }
}

--- --- UPDATE 添加了2个类(下面的Baz和Bar)并使用setter更新了Foo并覆盖了toString()。

首先运行Baz我希望它每秒都以最新的值打印foo.toString()。

然后运行Bar,它首先更新Foo的字段,然后每秒打印foo.toString()。 Bar的更新仅对Bar可见,而不是Baz。

Baz的输出:

1443284013576 Foo {someString =' a',someNum = 1}

1443284014576 Foo {someString =' a',someNum = 1}

1443284015576 Foo {someString =' a',someNum = 1}

1443284016577 Foo {someString =' a',someNum = 1}

1443284017577 Foo {someString =' a',someNum = 1}

1443284018577 Foo {someString =' a',someNum = 1}

Bar的输出:

1443284016416 Foo {someString =' abc',someNum = 2}

1443284017417 Foo {someString =' abc',someNum = 2}

1443284018417 Foo {someString =' abc',someNum = 2}

1443284019418 Foo {someString =' abc',someNum = 2}

1443284020418 Foo {someString =' abc',someNum = 2}

public class Baz {
    public static void main(String[] args) throws InterruptedException {
        Foo foo = Foo.getInstance();
        while(true){
            System.out.println(foo);
            Thread.sleep(1000);
        }
    }
}


public class Bar{
    public static void main(String[] args) throws InterruptedException {
        Foo foo = Foo.getInstance();
        foo.setSomeNum(2);
        foo.setSomeString("abc");
        while(true){
            System.out.println(foo);
            Thread.sleep(1000);
        }
    }
}

更新:一些愚蠢的错别字

4 个答案:

答案 0 :(得分:1)

Java要求程序员明确地包含一些机制,以便synchronizing访问多线程程序中的共享资源。 Java为此提供了许多功能,但初学者应该从类的所有相关方法的synchronized关键字开始。在您的示例中,如果不同步getInstance()方法,则可能会生成多个类的实例。如果未能同步您的其他方法,您将面临非确定性行为的风险。

要获得同步访问的好处,您只需将synchronized关键字添加到方法声明中,例如: public static synchronized Foo getInstance(){public synchronized void setSomeString(String someString) {

答案 1 :(得分:1)

您有两个独立的主要方法,因此您可能在单独的JVM中运行每个类。而是创建一个main方法,在不同的线程中运行每个类,然后运行它。

您还需要将Foo中的方法声明为synchronized或等效的,以保证所有线程都能看到更新。

public class Foo {
    private static Foo instance;
    private String someString;
    private int someNum;

    private Foo() {
        someString = "a";
        someNum = 1;
    }

    public synchronized static Foo getInstance(){
        if(instance == null) {
            instance = new Foo();
        }
        return instance;
    }

    public synchronized void setSomeString(String someString) {
        this.someString = someString;
    }

    public synchronized void setSomeNum(int someNum) {
        this.someNum = someNum;
    }

    @Override
    public synchronized String toString() {
        return "Foo{" +
                "someString='" + someString + '\'' +
                ", someNum=" + someNum +
                '}';
    }
}

public class Baz implements Runnable {
    public void run() {
        Foo foo = Foo.getInstance();
        while(true) {
            System.out.println("Baz: " + foo);
            try {
                Thread.sleep(1000);
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


public class Bar implements Runnable {
    public void run() {
        Foo foo = Foo.getInstance();
        foo.setSomeNum(2);
        foo.setSomeString("abc");
        while(true) {
            System.out.println("Foo: " + foo);
            try {
                Thread.sleep(1000);
            } catch(InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        new Thread(new Bar()).start();
        new Thread(new Baz()).start();
    }
}

答案 2 :(得分:0)

是的,您可以使用setter和getter。要从另一个类访问setter,请使用Foo.getInstance()。setSomeString(someString)。

答案 3 :(得分:-1)

从您的单件类,如果创建了对象,则不允许任何对象修改someNum&由于单例模式,someString值。在多线程应用程序中可能有机会破坏单例模式。这将导致您的价值不可靠。