synchronized 加锁Integer对象(数据重复)详解

场景描述:多线程输出1到100,对静态Integer对象加锁,synchronized代码块中操做Integer对象,发生线程安全问题(数据重复)java

代码:数组

public class MyRunnableTest implements Runnable {
    public static Integer i = new Integer(0);

    @Override
    public void run() {
        while(true){
            synchronized (i) {
                if(i<100){
                    i++;
                    System.out.println(Thread.currentThread()+"i = " + i);
                }else {
                    break;
                }
            }
        }
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new MyRunnableTest());
        Thread t2 = new Thread(new MyRunnableTest());
        t1.start();
        t2.start();
    }

}

运行结果:缓存

Thread[Thread-0,5,main]i = 1
Thread[Thread-1,5,main]i = 3
Thread[Thread-1,5,main]i = 4
Thread[Thread-1,5,main]i = 5
Thread[Thread-1,5,main]i = 6
Thread[Thread-0,5,main]i = 5
Thread[Thread-1,5,main]i = 7
Thread[Thread-0,5,main]i = 8
Thread[Thread-1,5,main]i = 9
Thread[Thread-0,5,main]i = 10
Thread[Thread-1,5,main]i = 11
Thread[Thread-0,5,main]i = 12
Thread[Thread-1,5,main]i = 13

 

从运行结果中能够发现发生了线程安全问题,为何呢?为何synchronized无效了。安全

个人排查思路:多线程

一、由于没有进行任何的额外操做,因此首先定位问题在i++处并发

经过javap分析字节码命令,总结:ide

能够看出:i++的实际操做为:Integer.valueOf(Integer.intValue(i)+1)测试

咱们在看看Integer中vauleOf的源码:spa

public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

cache[]数组初始化: 
  cache = new Integer[(high - low) + 1];
  int j = low;
  for(int k = 0; k < cache.length; k++)
  cache[k] = new Integer(j++);

 

其中low为-128,hight为127。能够了解到,当i的值为-128~127时,是从IntegerCache中取的(能够理解为从缓存中取的),超过部分是new出来的对象。线程

二、目前咱们慢慢开始解开了问题的面纱,每当i发生自增后,所对象改变了,这里咱们还须要清楚一下,synchronized在锁对象发生改变时(测试发现,引用类型对象的内在属性变化不会释放锁)会当即释放锁。因此这里就会出现线程安全问题,并且在单核的运行环境下,全部的线程是并发执行而不是并行执行,当咱们运行到system.out.println时,锁已经释放了,假如这边t1线程(当前运行的线程,i=1的状况)释放CPU资源,t2执行,这时i等于2(i++以前),当执行到system.out.println时释放cpu资源(此时i=3),t1执行,i此时已经为3了,因此输出3,在释放cpu资源,t2执行,输出3,这时出现了输出重复值的状况。

相关文章
相关标签/搜索