首先回顾一下包装类。
-
包装类可以为null,而基本类型不可以。这使得包装类可以用于POJO中,而基本类型不行,因为数据库的查询结果可能是null,用基本类型的话,因为要自动拆箱,就会抛出NullPointerException。
-
基本类型在栈中直接存储具体数值,而包装类存储的是堆中的引用,基本类型比包装类更高效。
-
通过Integer.valueOf(n)装箱,通过Integer对象调用intValue()方法拆箱。jdk1.5后自动拆装箱。
-
new Integer(123) 与 Integer.valueOf(123) 的区别在于:
- new Integer(123) 每次都会新建一个对象;
- Integer.valueOf(123) 会使用缓存池中的对象,多次调用会取得同一个对象的引用。 在 Java 8 中,Integer 缓存池的大小默认为 -128~127。编译器会在自动装箱过程调用 valueOf() 方法,因此多个值相同且值在缓存池范围内的 Integer 实例使用自动装箱来创建,那么就会引用相同的对象。
回到正题,当用Integer等包装类做synchronized的锁时,会出现如下问题:
- 对Integer类型的变量做了修改,如自增操作。这里的i++实际上是i = new Integer(i+1),所以执行完i++后,i已经不是原来的对象了,同步块自然就无效了。
- 若是创建两个相同值并超出缓存池大小的包装类对象,其实是两个对象,也就是两把不同的锁。 解决:可以用AtomicInteger保证线程安全。