并发编程(1):线程安全

原子性:

1、Atomic包:通过CAS这个底层方法实现原子性。LongAdder在AtomicLong的基础上将单点的更新压力分散到各个节点,在低并发的时候通过对base的直接更新可以很好的保障和AtomicLong的性能基本保持一致,而在高并发的时候通过分散提高了性能。缺点是LongAdder在统计的时候如果有并发更新,可能导致统计的数据有误差。 

 

2、synchronized关键字:

修饰代码块和方法时,作用域是当前调用对象,每个对象之间相互不影响;

代码块被sync了class和静态方法被sync作用域是被调用块和被调用方法,每个对象会顺序访问,线程安全;

synchronized不会被继承,因为它不属于修饰符;

synchronized(this/xxx.class)区别

 

3、volatile关键字:只能保证每次取值只是最新的,不能保证写入时是最新的,不是线程安全的

 

4、Lock类:是concurrent包里的,基于volatile和unsafe.CAS实现的,属于乐观锁

 

不可变对象:

final修饰的变量不可以使用等号,但可以修改对象里面的值。

想要对象里的值不可变:

Collections.unmodifableXXX

Guava包里的ImutableXXX

final和不可变类可以保证线程安全

 

线程不安全:

StringBuilder和StringBuffer

 

SimpleDataFormat是线程非安全的,如果需要:

1、放到线程方法内,每次重新New。

2、使用synchronized同步(影响性能)

3、使用ThreadLocal

 

org.joda.datetime.format.DateTime是线程安全的,推荐使用

 

同步容器:

Vector(虽然加了sync,但使用不当,还是会出现线程安全问题,表现在删除下标为x的数据,导致下标x的数据已经不存在了,但另外一个线程还是通过下标x去get数据。for循环的size是固定的,但是数组的实际size已经变了)

HashTable

Collections.syncchronizedXXX(返回SynchronizedList或者SynchronizedRandomAccessList)

 

并发容器:

ArrayList --> CopyOnWriteArrayList:读的时候是旧数组;写的时候,把旧的数组

posted @ 2020-06-10 15:02  北大教授  阅读(97)  评论(0)    收藏  举报