关于单例和线程的奇怪问题

实现了一个存储文本的单例对象,在两个线程里不停地存入读取
单例类

 public class Singleton {
    private static Singleton defaultInstance;
    private String info="";
    private Singleton(){};
    public static Singleton getInstance(){
        if(defaultInstance==null){
            synchronized (Singleton.class) {
                if(defaultInstance==null){
                    defaultInstance=new Singleton();
                }
            }
        }
        return defaultInstance;
    }
    public String getInfo() {
        return info;
    }
    public void setInfo(String info) {
        this.info = info;
    }
}

线程类

public class singleton_thread  extends Thread{
    private String name="";
    private Singleton singleton = Singleton.getInstance();
    public singleton_thread(String string) {
        name=string; 
    }
    public Singleton getSingleton() {
        return singleton;
    }
    public void run() {

         int i=1;
         while(i<1000){
            System.out.println(name+"第"+i+"次读取:"+singleton.getInfo());
            i++;
            singleton.setInfo(name+"的第"+i+"次注入值");
         }
     }
}

测试类

public class test {

    public static void main(String[] args) {
        Singleton singleton = Singleton.getInstance();
        singleton_thread thread1= new singleton_thread("A");
        singleton_thread thread2= new singleton_thread("B");
        singleton.setInfo("确认单例:"+thread1.getSingleton().equals(thread2.getSingleton()));
        thread1.start();
        thread2.start();
    }
}

输出如下:
A第1次读取:确认单例:true
B第1次读取:确认单例:true
A第2次读取:A的第2次注入值
B第2次读取:B的第2次注入值
A第3次读取:A的第3次注入值
B第3次读取:B的第3次注入值
A第4次读取:A的第4次注入值
B第4次读取:B的第4次注入值
...
问题来了,
按这个顺序
A第2次读取:A的第2次注入值
这个时候单例的值应该是
A的第3次注入值
所以下一行应该是
B第2次读取:A的第3次注入值
但实际上是
B第2次读取:B的第2次注入值

这是为什么??

然后,在thread的while中加入sleep(10)后
输出
A第1次读取:确认单例:true
B第1次读取:确认单例:true
A第2次读取:B的第2次注入值
B第2次读取:B的第2次注入值
A第3次读取:B的第3次注入值
B第3次读取:B的第3次注入值
A第4次读取:B的第4次注入值
B第4次读取:B的第4次注入值
这个时候能对上了,说明的确存在互相覆盖,只不过ab同时在存入。B晚一点而已

那么在不sleep的时候为什么线程之间完全不互相覆盖,反而有点像是A执行完了才执行B,只不过打印的时候乱掉了。如果不是的话,是不是意味着单例是无效的?
问这个问题是担心如果是没有sleep的场景(比如用户高频率的调用spring的controller)会不会发生意想不到的情况

单例的使用
熟悉单例的结构,适用场景

实现要求:
java控制台实现 每秒输出单例里面的数据和数据库里面输出的数据,并对比性能开销
附加要求:数据库的100W条数据统计之和、数据库读出之后统计之和、内存存储数据计算之
和 文件数据读取后统计之和(存储格式自己定义),并输出各个过程的的时间开销

这个你会么?

1、你单例的是singleton这个对象,多线程修改和读取的是它的属性,对象是一直保持不变的,只不过属性在一直变而已
2、用户高频率的调用spring的controller,要想不出现类似的情况,只要不再controller里将业务数据作为公共变量就可以了,即不作为controller里的属性,
所有的业务数据都是方法里的局部变量