Java单例模式-对实例化变量的更新
想弄明白关于单身模式的一些事情 如果我实现了如下所示的单例模式,我该怎么做才能让其他类更新并看到字段someString和somesint的更新 从我读到的关于Singleton模式的内容来看,不变性不是先决条件之一。因此,从技术上讲,我可以为字段设置setter方法并对其进行更改,使这些更改对其他类可见吗?例如,如果我有另外两个类实现Runnable并每隔几秒钟打印一次Foo的字段。我尝试了这个,结果是每个类只看到自己的更新,而其他类则没有Java单例模式-对实例化变量的更新,java,design-patterns,singleton,Java,Design Patterns,Singleton,想弄明白关于单身模式的一些事情 如果我实现了如下所示的单例模式,我该怎么做才能让其他类更新并看到字段someString和somesint的更新 从我读到的关于Singleton模式的内容来看,不变性不是先决条件之一。因此,从技术上讲,我可以为字段设置setter方法并对其进行更改,使这些更改对其他类可见吗?例如,如果我有另外两个类实现Runnable并每隔几秒钟打印一次Foo的字段。我尝试了这个,结果是每个类只看到自己的更新,而其他类则没有 public class Foo { pri
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 +
'}';
}
}
---更新---
添加了2个类(下面的Baz和Bar),并使用setter更新了Foo,并重写了toString()
首先运行Baz,我希望它每秒打印foo.toString(),并使用最新的值
然后运行Bar,它首先更新Foo的字段,然后每秒打印Foo.toString()。来自Bar的更新仅对Bar可见,对Baz不可见
来自Baz的输出:
1443284013576 Foo{someString='a',somesnum=1}
1443284014576 Foo{someString='a',someNum=1}
1443284015576 Foo{someString='a',someNum=1}
1443284016577 Foo{someString='a',somesnum=1}
1443284017577 Foo{someString='a',someNum=1}
1443284018577 Foo{someString='a',somesnum=1}
条形图的输出:
1443284016416 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);
}
}
}
1443284017417 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);
}
}
}
1443284018417 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);
}
}
}
1443284019418 Foo{someString='abc',somesnum=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);
}
}
}
1443284020418 Foo{someString='abc',somesnum=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);
}
}
}
更新:一些愚蠢的打字错误是的,你可以使用setter和getter。。要从另一个类访问setter,可以使用Foo.getInstance().setSomeString(someString) 从singleton类中,如果创建了对象,则由于singleton模式,不允许任何对象修改someNum和someString值。在多线程应用程序中,可能有机会打破单例模式。这将导致您的值不可靠。Java要求程序员在多线程程序中明确包含一些访问共享资源的机制。Java为此提供了许多特性,但是初学者可能应该从类中所有相关方法的synchronized关键字开始。在您的示例中,如果不同步getInstance()方法,可能会生成多个类实例。如果未能同步其他方法,则可能会出现不确定性行为 要获得同步访问的好处,只需在方法声明中添加
synchronized
关键字,例如。
public static synchronized Foo getInstance(){
和public synchronized void setSomeString(String someString){
您有两个独立的主方法,因此您可能在单独的JVM中运行每个类。相反,创建一个主方法,在不同的线程中运行每个类,然后运行该主方法
您还需要将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();
}
}
仅仅是一个FYI,对于线程安全,您应该考虑使用<代码> GETStaseNo.()/Case>一个同步方法。您可以用您所尝试的设置器来发布示例吗?当您声明<代码> GETSimule方法时,会发生什么情况??@BYTERIDER请参见above@JamesKPolk如果我的问题与同步有关,我不希望看到更新或获得ConcurrentModificationException吗?请参阅我的更新。问题仍然存在于上述类中。请参阅我的更新。我不希望不可变。只是将单个变量的更新发布到其他类的一种方法。请参阅