java并发编程(一)

开始更新一发java并发编程的博客

1、多线程不一定块,当并发执行累计操作不超过百万次时,速度会比串行累加操作要慢。这是因为多线程有创建个上下文切换的开销。上下文每一秒切换1000多次。
2、减少上下文切换的方法

无锁并发编程:
多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁。
CAS算法:
java的Atomic包使用CAS算法来更新数据,而不需要加密
使用最少线程:
避免创建不需要的线程
协程:
在单线程里实现多任务的调度,并在单线程里维护多个任务间的切换

3、避免死锁的方法

避免一个线程同时获取多个锁
避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制
对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况

4、volatile
volatile是轻量级的synchronized,他在多处理器开发中保证了共享变量的可见性。
可见性:当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。不会引起线程上下文的切换和调度。

相关定义:

内存屏障:一组处理器指令,用于实现对内存操作的顺序限制
缓冲行:CPU高速缓存中可以分配的最小存储单位,处理器填写缓存行时会加载整个缓存行,现
代CPU需要执行几百次CPU指令
原子操作:不可中断的一个或一系列操作
缓存行填充:档处理器识别到从内存中读取操作数是可缓存的,处理器读取整个高速缓存行到适
当的缓存
缓存命中:如果进行高速缓存行填充操作的内存位置仍然是下次处理器访问的地址时,处理器从
缓存中读取操作数,而不是从内存读取
写命中:当处理器将操作数写回到一个内存缓存的区域时,它首先检查这个缓存的内存地址是否
在缓存行中,如果存在一个有效的缓存行,则处理器将这个操作数写回到缓存,而不是写回到内
存,这个操作被称为写命中
写缺失:一个有效的缓存行被写入到不存在的内存区域

使用volatile关键字的共享变量在进行写操作时,会多执行两步:

a、将当前处理器缓存行的数据写回到系统内存
b、这个写会内存的操作会使在其他CPU里缓存了该内存地址的数据无效

在多处理器下,为了保证各个处理器的缓存是一致的,就会实现缓存一致性协议,每个处理器通过嗅探在总线上的传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址呗修改,就会将当前处理器的缓存行设置成无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。

vloatile实现原则

a、Lock前缀指令会引起处理器缓存回写到内存
b、一个处理器的缓存回写到内存会导致其他处理器的缓存无效

volatile的使用优化

追加字节优化性能:
一般来说可以把volatile变量追加到64字节

5、synchronized的实现与应用
java中的每一个对象都可以作为锁。具体表现为以下三种形式

对于普通同步方法,锁时当前实例对象
对于静态同步方法,锁时当前类的Class对象
对于同步方法块,锁时Synchonized括号里配置的对象

JVM基于进入和退出Monitor对象来实现方法同步和代码块同步,但两者的实现细节不太一样。

java对象头

synchronized用的锁是存在Java对象头里的。如果对象是数组类型,则虚拟机用3个字宽存储对
象头,如果对象是非数组类型,则用2字宽存储对象头。

猜你喜欢

转载自blog.csdn.net/xielinrui123/article/details/80626941