今天早高峰在地铁上突然有一个疑惑:String 是immutable是为了保证线程安全,Integer也是Immutable,为什么并发的时候建议使用AtomicInteger呢?
晚上回来查阅相关资料得出总结:
1 2 3 4 5 6 7 8 9 10 11 12 13
| String a="test"; String b="test"; System.out.println(a==b); System.out.println(System.idntityHashCode(a)); System.out.println(System.identityHashCode(b)); 输出:true 851664923 851664923 //为什么有觉得可变呢? String a="test"; a="test1"
|
a就变成了test1,其实在这里是新建了一个”test1”字符串对象(如果常量池没有这个值的话就是新建)。然后将变量引用指向它。注意:这里并没有修改”test”这个变量的内部状态,”test”这个字符串对象是线程安全的。
除非你用final修饰,否则所有的变量指向都是可变的。
这种情况下要保证线程安全性:
- 可以考虑使用volatile确保可见性。
- 可以使用final修饰
- 你可以使用AtomicReference之类的原子对象,对于Integer等也有AtomicInteger之类的
- 对相应代码区域加锁
有兴趣可以查看这两篇文章:
String是线程安全的吗?那String岂不是不能进行同步?
Java多线程系列–“JUC原子类”04之 AtomicReference原子类
综上:String Immutable为了线程安全知识相对的(字符串常量值不可变),但是引用可变,所以为了并发的时候线程安全,可以使用上面所说的几种方案。(如果有更好的认识深度,欢迎讨论)有兴趣可以查看我之前写的一篇文章关于介绍:String为什么是final修饰的
问题:
- int和Integer有什么区别?谈谈Integer的值缓存范围?
知识点
- Integer缓存或者String 常量池缓存用到的设计模式-享元模式。
相关代码(好记性不如烂笔头,代码是最好的理解):
1 2 3 4 5 6 7 8 9
| package yonghui.cn.firstthread.flyweight; /** * 作者:huangchen on 2018/7/26 20:57 * 邮箱:huangchen@yonghui.cn */ public interface IBike { void biliing(int time); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package yonghui.cn.firstthread.flyweight; /** * 作者:huangchen on 2018/7/26 20:58 * 邮箱:huangchen@yonghui.cn */ public class ShareBike implements IBike { private int price;//单价 private int total;//总价 @Override public void biliing(int time) { System.out.println("total price is" + price * time); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package yonghui.cn.firstthread.flyweight; import java.util.HashMap; /** * 作者:huangchen on 2018/7/26 20:11 * 邮箱:huangchen@yonghui.cn */ public class FlyWeightFactory { private HashMap<String, IBike> map = new HashMap<>(); public IBike getIBike(String name) { IBike iBike; if (map.containsKey(name)) { System.out.println("押金已经交过了" + name); iBike = map.get(name); return iBike; } else { System.out.println("押金没有交,开始交押金299元"); iBike = new ShareBike(); map.put(name, iBike); return iBike; } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package yonghui.cn.firstthread.flyweight; /** * 作者:huangchen on 2018/7/26 20:16 * 邮箱:huangchen@yonghui.cn */ public class Client { public void test(){ FlyWeightFactory flyWeightFactory = new FlyWeightFactory(); IBike ofo = flyWeightFactory.getIBike("ofo"); ofo.biliing(2); IBike mobike = flyWeightFactory.getIBike("mobike"); mobike.biliing(1); IBike ofo1 = flyWeightFactory.getIBike("ofo"); ofo1.biliing(3); } }
|
关于享元模式有兴趣可以参考:Android的设计模式-享元模式。
- 自动装箱、自动拆箱发生在编译阶段。静态工厂方法valueof()使用了缓存机制,自动装箱的时候,缓存机制起作用。实际开发中,避免无意的装箱、拆箱行为(不管是内存使用还是运行速度、10w个Java对象比10w整数的开销要大得多,光是对象头空间占用已经是数量级的差距了)。
对象的内存结构:对象由对象头、对象实例、对齐填充三部分组成。具体有兴趣可以参考:Java对象内存布局
回答问题:
int是我们常说的整形,是八大基本数据类型之一,占4个字节,取值范围2的31次方减去1,Java需要号称一切都是对象,但是基本数据类型是个例外。
Integer是int对应的包装类,他有一个int类型存字段(private final修饰,Immutable),并且提供了基本操作,比如数字运算、int和字符串之间的转换。在Java5中,引入了自动装箱、拆箱功能。Java根据上下文,自动进行转换,极大简化了相关编程。
关于Integer的值缓存,这涉及Java5的内一个改进。大部分数据操作都集中在有限的、较小的数值范围,因而,在Java 5 中新增了静态工厂方法valueof,在调用它的时候会利用一个缓存机制,带来了明显的性能改进。按照Javadoc,这个值默认缓存-128-127之间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| //Integer部分源码 //Immutable private final /** * The value of the {@code Integer}. * * @serial */ private final int value; /** * Returns an {@code Integer} instance representing the specified * {@code int} value. If a new {@code Integer} instance is not * required, this method should generally be used in preference to * the constructor {@link #Integer(int)}, as this method is likely * to yield significantly better space and time performance by * caching frequently requested values. * * This method will always cache values in the range -128 to 127, * inclusive, and may cache other values outside of this range. * * @param i an {@code int} value. * @return an {@code Integer} instance representing {@code i}. * @since 1.5 */ public static Integer valueOf(int i) { assert IntegerCache.high >= 127; if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
|
参考:
声明:此为原创,转载请联系作者
作者:微信公众号添加公众号-遛狗的程序员 ,或者可以扫描以下二维码关注相关技术文章。
当然喜爱技术,乐于分享的你也可以可以添加作者微信号: