java并发编程和高并发之线程安全策略

46 篇文章 0 订阅
12 篇文章 0 订阅

一、不可变对象:

1、有一种对象,发布时就是安全的,这个对象就是不可变对象。

2、如果想创建一个不可变的类,可参考使用最多的String类。当满足以下三个条件时才会是不可变对象。

   即不可变对象需要满足的条件:

    》对象创建以后其状态就不能修改;——》声明为final

    》对象所有域都是final类型;

    》对象是正确创建的(在对象创建期间,this引用没有逸出)——》对 变量不提供set方法,将所有可变的成员声明为final,通过构造器初始化所有成员进行深度拷贝。在get方法中不直接返回对象本身而是返回克隆对象,并返回对象的拷贝。

3、基础:

》final关键字:类、方法、变量

    》修饰类:不能被继承。如果希望一个类永远不能被继承,就用final进行修饰。java基本类型的封装类都是用final修饰的不可继承的类。final 类中的成员变量可以根据需要声明为final,但final类中的所有成员方法都会被隐式地指定为final 方法。注意:在用final修饰时,要谨慎地考虑。

  》修饰方法:1、锁定方法不被继承类修改;2、效率(旧版本);

                    扩展:任何一个类的private方法会被隐式地指定为final方法。

  》修饰变量:基本数据类型变量、引用类型变量。如果final修饰基本类型变量,那么该变量一旦被初始化,其值将不可被修改。而如果final修饰一个引用类型的变量,则该变量只能指向初始化时的对象,不能再被更改指向另外的对象。但是特别注意刚才所述的最后一条:不可以改变引用变量指向的对象,是指引用变量初始化后,其值表示的是某个对象的地址。因为final修饰的变量一旦初始化,则它的值不可改变,即引用变量的值一直是初始化时某个对象的地址值。故不可改变它(使它指向其他的对象),但可以通过一些方法,让引用变量指向的对象本身发生改变。好比一根绳子牵着一个盒子,这根绳子生生世世只能拉着这个盒子,而无法修改拉住其他盒子。但是盒子本身可以更改其内容物,比如在盒子中增减存放不同的东西。即引用变量表示的对象除了地址值无法发生改变,其其他属性可以改变。

4、代码演示,final修饰基本变量和引用变量的区别;

如果基本类型初始化之后被修改,编译时会直接爆红。

如果是引用类型,比如下方举例的map, map只能指向第一次初始化时创建的这个数组,

但是map本身的key  value值是可以被修改的。如下方示例。这点特别注意!!!!!

因此,final修饰引用变量类型,是存在一定的线程安全问题的。(所以克隆时,有深克隆,要求把涉及到的所有引用类型要克隆一遍再使用)

注:上方创建map时使用了guava包,下方可看下其导入的包

运行时会抛出异常

5、java中除了上述final关键字,可以声明不可变对象,还有其他方法吗?

答案:有的,具体如下:

》包括 jdk中的Collections.unmodifiableXXX:Collection 、List、Set、Map ...

  使用方法:把自己创建的Collection等对象,放到如上对应的unmodifiableXXX中,该对象即不可变。

》包括谷歌的Guava 中:ImmutableXXX:Collection 、List、Set、Map ...,

  使用方法:声明一个Immutable开头的对象时,只要完成其初始化方法,就已经是个不可变对象了。

但是与final修饰变量不可变的表现不同,该种方式是在运行时抛出异常出来。

运行时可以发现:

 即发现unmodifiableMap 类中有很多类似的unmodifiXXX的方法,如下图:

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值