多线程并发学习笔记
内存模型:
url:http://www.54tianzhisheng.cn/2018/02/28/Java-Memory-Model/#
1.volatile关键字
由于内存模型的可见性,多线程操作共享数据时,可能由于主存刷新不及时,导致多线程得到的共享数据结果不一致.volatile关键字可以保证内存中数据的可见性,及时刷新主存,但是内存中对数据的操作不可重排序
volatile 变量自身具有下列特性:
可见性:对一个 volatile 变量的读,总是能看到(任意线程)对这个 volatile 变量最后的写入。
原子性:对任意单个 volatile 变量的读/写具有原子性,但类似于 volatile++ 这种复合操作不具有原子性。
volatile 写-读的内存定义
当写一个 volatile 变量时,JMM 会把该线程对应的本地内存中的共享变量值刷新到主内存。
当读一个 volatile 变量时,JMM 会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量。
相较于synchronize是一种较为轻量的同步策略,有以下两点不同
1.不具备互斥性
2.不能保证变量的原子性
2.原子变量与CAS算法
java1.5后提供了原子变量的类,其中包括了很多支持并发操作的常用数据类型以及常用数据结构:java.util.concurrent.atomic
原子数据类型特点:
1.默认使用volatile关键字,保证内存可见性
2.使用CAS算法保证原子性
2.1CAS算法(CompareAndSwap)
CAS算法是硬件对于并发操作共享数据的支持
ACS包含三个值
内存值:V 预估值:A 更新值:B
当且仅当 V==A时,V=B,否则不做操作,保证了数据的原子性
CAS算法相较于synchronized,有点在于:不阻塞,无锁,效率高
hashTable虽然单个操作时线程安全,但是同时存在复合操作时会存在线程不安全的情况,所以针对于这种情况,一般使用concurrentHashMap
concureentHashMap,在1.8之前使用"锁分段"机制,每个链表使用不同锁来提高效率
jdk1.8后,使用CAS算法,废弃锁分段机制
3.多线程实现方式
1.实现runnable接口
2.继承Thread
3.实现Callable接口
实现Callable接口可以等待获取result,会等待线程运行完成,类似countDownLatch
FeatureTask<> result = newFeatureTask<>(new Callable())
4.Lock
此处就不做介绍:
参考:https://www.cnblogs.com/wuhan729/p/8601108.html
5.线程池(提供线程队列)
Executors
ExecutorService
FixedThreadPool:固定大小线程池
CachedThreadPool:缓存线程池,可自动变更数量
SingleThreadExecutor:单个线程线程池
ScheduledExecutorsService
ScheduledThreadPool: 固定大小调度线程池,可定时执行