2011-03-19 193 views
0

我有一个程序使用单例模式。我需要使用线程,记住使用线程机械化之前和之后的输出应该是相同的。我的意思是避免线程忽略单例并创建更多一个对象的“断线模式”。但是,我失败了。我试图使用“同步”,但没有改变。同样的错误结果。java编程和java单线程多线程问题(单线程与多线程)

我主要用了Runnable

public class Main implements Runnable { 
    Main(){} 
    public void run() 
     { 
      Counter[] counters = new Counter[5]; 
      for(int i = 0; i < counters.length; i++) 
       { 
        counters[i] = Counter.getCounter(); 
       } 
      for(int i = 0; i < counters.length; i++) 
       { 
        counters[i].increment(); 
        System.out.println("counter[" + i + "] = " + counters[i]); 
       } 

      for(int i = 0; i < 5; i++) { 

       counters[i].decrement(); 
       System.out.println("counter[" + i + "] = " + counters[i]); 
       }} 

    public static void main(String[] args) 
    { 

     Main m1=new Main(); 
     Main m2=new Main(); 
     Main m3=new Main(); 
     new Thread(m1).start(); 
     new Thread(m2).start(); 
     new Thread(m3).start(); 
    } 
} 

它适用Singleton模式

public class Counter { 

     private static Counter myInstance = null; 


     public static Counter getCounter() 
     { 
      if(myInstance == null) 
       { 
        synchronized (Counter.class)     { 
         if(myInstance == null) 
         { 
          myInstance = new Counter(); 
         } 
        } 
       } 




     return(myInstance); 


     } 

     private int myCounter; 

     private Counter() { 
     myCounter = 0; 
     } 

     public void increment() { 
     myCounter++; 
     } 

     public void decrement() { 
     myCounter--; 
     } 

     public String toString() { 
     return(Integer.toString(myCounter)); 
     } 
    } 
+0

'java.util'应该有一个懒惰的评价'Lazy'类;这经常是需要的,而人们不知道如何正确地做。 “内部类单身人士”和“枚举单身人士”是黑客,只为全球状态工作。 Spring只是让你在xml中编写相同的东西。出于某种原因,人们认为xml不是代码。对他们的老板很好。 – irreputable 2011-03-20 03:24:00

回答

3

双重检查锁定模式用于在Java中被打破的其他类。我不知道新内存模型是否修复它。

除了“我真的需要一个单身人士吗?”这个问题之外,单身人士购买你的懒惰实例化到底是什么?

Nothing

如果你的单例实例化的代价很高,并且有可能你不使用它,这可能是合理的。但这里没有一个是这种情况。

所以,如果你一定要,写这样的:

public class Counter 
{ 
    // Edited at the recommendation of Sean and "Effective Java"; see below 
    private static class InstanceHolder 
    { 
     private static final Counter INSTANCE = new Counter(); 
    } 

    private Counter() {} 

    public static Counter getInstance() { return InstanceHolder.INSTANCE; } 

    // The rest of the implementation follows. 
} 
+0

你可能想要在声明时初始化'instance'变量。 – CarlosZ 2011-03-19 21:37:47

+0

该死的药物.....感谢指出。 – duffymo 2011-03-19 21:46:09

+0

其值得注意的是,类延迟加载,所以只使用'公共静态final'值或'enum'用一个数值很可能是一样的好,更简单/安全。 – 2011-03-19 21:58:46

6

不要使用双重检查单例模式,它不是做现代的方式,无论是损坏或没有。

单身在Java中应该使用任一内部类或枚举来实现(见Effective Java项目3:强制singleton属性与私有构造函数或枚举类型):

一)内部类的Singleton图案:

public class MySingleton{ 
    private MySingleton(){} 
    private static class InstanceHolder{ 
     private static final MySingleton INSTANCE = new MySingleton(); 
    } 
    public static MySingleton getInstance(){ 
     return InstanceHolder.INSTANCE; 
    } 

} 

b)中的Enum Singleton模式

public enum MySingleton{ 
    INSTANCE; 

    public static MySingleton getInstance(){ 
     return INSTANCE; 
    } 

} 
+1

有效的Java是在这里提到的正确的书(+1)。 – atamanroman 2011-03-19 21:39:37

+0

链接到枚举不再工作 – 2016-12-29 12:40:40

+0

@ BenSchmidt谢谢。维基百科的文章被改变,不幸的是,删除链接 – 2016-12-29 13:37:43

0

您必须同步整个方法。 Here's why your code is wrong

最有意义的是在静态块中初始化singleton并且不检查任何东西,除非你有成千上万个通常不用的singleton类,它不会影响性能。

+0

“...成千上万....单身......” - ? – duffymo 2011-03-19 21:30:49

+0

@duffymo:他的意思是成千上万的不同类别,其是单身,这的确是可能的 – atamanroman 2011-03-19 21:41:34

+0

是的,我知道他的意思的。可能?是。可取?我对此表示怀疑。 – duffymo 2011-03-19 22:44:42

1

不完全确定你要达到的目标,但有一些错误。

  • increment/decrement不是线程安全的。 ++和 - 不是原子操作。您需要同步这两种方法或使用AtomicInteger及其原子增量/减量方法

  • 您正在读取与修改相反的计数器的值,因此另一个线程可能已更改为更新和读取之间的值它为println。我会建议使用的AtomicInteger和递增/递减返回新值,如果你需要显示它

  • 综观以上两点你也许可以用一个静态的AtomicInteger实例

  • 双重检查更换计数器锁定在getCounter可能被破坏。我不确定静态的行为在同步的可见性范围之外。为了安全起见我会删除最初的零检查

  • 你需要的输出是不会出来的验证码。每个线程(其中有3个线程)采用相同的计数器实例,5次,每次都打印两次。我的数字是30个输出语句。

  • 这些输出的顺序永远无法预测,因为线程正在竞争增加/减少(单个)计数器值,因此它可能会以随机方式上下颠簸。加上数值的打印可能出现无序的线程竞争太

  • 这是不好的做法,对一类同步,尤其是公共类和其他代码可以sychronize它与你的锁干扰。最好的办法就是对那个

  • 一个private static final Object lock = new Object();和同步你并不需要把()围绕return语句

希望一些帮助!多线程代码是一项困难/危险的业务,所以请谨慎行事!也许如果你问了一个问题,说明你的目标,某人可以用一些提示和/或模型答案来帮助你。

+0

+1他不仅仅有一个问题 – irreputable 2011-03-20 03:16:31