简体   繁体   English

Java编程和问题Java单例多线程(singleton与multithreading)

[英]java programing and the problem java singleton multithreading (singleton vs multithreading )

I have a program which uses singleton pattern. 我有一个使用单例模式的程序。 I need to use threads with it taking in mind the output should be the same before and after using threads mechanize. 我需要使用线程,并记住使用线程机械化前后的输出应该相同。 I mean to avoid the case of "broken pattern" where the thread ignore the singleton and create more the one object. 我的意思是避免出现“中断模式”的情况,即线程忽略单例并创建更多一个对象。 But, I failed .I tried to use the “synchronized”, but nothing change. 但是,我失败了。我尝试使用“同步”,但没有任何变化。 the same wrong result. 同样的错误结果。

My main with the 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(); 
    }
}

The other class which applies the singleton pattern 另一类应用单例模式

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

Don't use the double-checked singleton pattern, it's not the modern way to do it, whether it's broken or not. 不要使用经过检查的单例模式,这不是现代的方法,无论它是否损坏。

Singletons in Java should be implemented using either an inner class or an enum (see Effective Java Item 3: Enforce the singleton property with a private constructor or an enum type ): Java中的单例应该使用内部类或枚举来实现(请参阅有效的Java项目3: 使用私有构造函数或枚举类型强制执行singleton属性 ):

a) Inner Class Singleton Pattern: a)内部类单例模式:

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 Pattern b)枚举单例模式

public enum MySingleton{
    INSTANCE;

    public static MySingleton getInstance(){
        return INSTANCE;
    }

}

Double checked locking used to be broken in Java. 双重检查锁定曾经在Java中被打破。 I don't know if the new memory model fixes it. 我不知道新的内存模型是否可以解决它。

Besides the question "Do I really need a Singleton?", what on earth is lazy instantiation of the Singleton buying you? 除了“我真的需要一个Singleton吗?”这个问题之外,Singleton的懒惰实例向您提供了什么?

Nothing . 没事

It might be justifiable if your Singleton was very expensive to instantiate and there was a possibility that you might not use it. 如果您的Singleton实例化非常昂贵,并且有可能不使用它,则可能是合理的。 But neither one is the case here. 但是这里没有人是这样。

So if you must, write it like this: 因此,如果必须的话,可以这样写:

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

Not entirely sure what you are trying to achieve but there's a few things wrong. 不能完全确定您要实现的目标,但是有一些错误。

  • increment/decrement are not thread-safe. increment/decrement不是线程安全的。 ++ and -- are NOT atomic operations. ++和-不是原子操作。 You either need to synchronize both these methods or use AtomicInteger with its atomic increment/decrement methods 您要么需要同步这两种方法,要么使用AtomicInteger及其原子增量/减量方法

  • You are reading the value of the counter separate from the modification of it so another thread may have changed to value in between updating and reading it for the println . 您正在读取计数器的值,而不修改计数器的值,因此在为println更新和读取计数器之间,另一个线程可能已更改为值。 I would suggest using AtomicInteger and returning the new value from increment/decrement if you need to display it 我建议使用AtomicInteger并从增量/减量返回新值(如果需要显示它)

  • Looking at the above two points you can probably replace Counter with a static AtomicInteger instance 看了以上两点,您可能可以用静态AtomicInteger实例替换Counter

  • The double-checked locking in getCounter is possibly broken. getCounter的双重检查锁定可能已损坏。 I'm not sure what the behaviour of statics is outside of a synchronized wrt to visibility. 我不确定静态的行为是否超出了可见性的同步范围。 To be safe I would remove the initial null-check 为了安全起见,我将删除初始的空检查

  • Your required output is not going to come out of this code. 您所需的输出不会从此代码中输出。 Each thread, of which there are 3, is taking the same instance of Counter, 5 times and printing twice each. 每个线程(其中有3个)都采用相同的Counter实例,即5次,每次打印两次。 By my count that is 30 output statements. 根据我的计算,这是30条输出语句。

  • The order of those outputs can never be predicted as you have threads competing to increment/decrement the (single) counter value so it may bump up and down in a random fashion. 这些输出的顺序永远无法预测,因为您有多个线程争相增加(或减少)(单个)计数器值,因此它可能以随机方式上下波动。 Plus the printing of the number value could appear out of order as the threads compete for that too 加上数字值的打印可能会出现混乱,因为线程也为此竞争

  • It is bad practice to synchronize on a class, especially a public class as other code can sychronize on it and interfere with your locking. 在类(尤其是公共类)上进行同步是不好的做法,因为其他代码可以在该类上同步并干扰您的锁定。 Best way is to have a private static final Object lock = new Object(); 最好的方法是拥有一个private static final Object lock = new Object(); and sync on that 并同步

  • You don't need to put () around return statements 您不需要将()放在return语句周围

Hope some of that helps! 希望其中的一些帮助! Multi-threaded code is a difficult/dangerous business so please do tread carefully! 多线程代码是一件困难/危险的事情,因此请谨慎行事! Perhaps if you asked a question stating your objective someone could help you out with some tips and/or a model answer. 也许如果您问一个问题说明您的目标,那么有人可以为您提供一些技巧和/或模型答案。

You have to synchronize the whole method. 您必须同步整个方法。 Here's why your code is wrong 这就是您的代码错误的原因

It makes most sense to initialize singleton in the static block and not check anything, unless you have thousands of typically unused singleton classes it will not affect the performance. 在静态块中初始化单例并且不检查任何内容都是最有意义的,除非您有数千个通常未使用的单例类,否则不会影响性能。

You missed volatile in 您错过了volatile

private static volatile Counter myInstance;

This should fix it, but do not do it. 这应该解决它,但不要这样做。 Use the Holder Pattern or eager initialization as shown. 如图所示,使用Holder Pattern或渴望初始化。 Or better, use Dependency Injection instead of the Singleton antipattern . 或更妙的是,使用Dependency Injection而不是Singleton反模式

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM