学习笔记(多线程篇)
基础概念
-
进程:系统进行资源分配和调度的最小单元,一个进程可以包 含多个线程
-
线程:操作系统运算调度的最小单位。它被包含在进程之中
-
java实现线程的方法: Thread Runnable callaAle 线程池
-
线程的状态
new -> Runnable -> Blocked -> waiting -> Timed_Waiting -> Terminated
-
线程的常用方法
start() -- 启动线程
sleep -- 线程进入休眠状态
wait/notify/notifyAll -- 现场进入等待状态 notifyAll 不会释放锁
join --- 放弃当前线程执行,让其他线程执行结束自己再执行
yield -- 线程礼让 运行状态->就绪状态
interrupt -- 中断线程
setDaemon(true) -- 设置当前线程为守护线程
getPriority() --设置现场优先级 取值:1-10 默认为5 1为最高
-
synchronized
Synchronized是一个同步关键字,在某些多线程场景下,如果不进行同步会导致数据不安全,而Synchronized关键字就是用于代码同步。
synchronized是一个对象锁,java每个对象头有两位会专门存放当前对象锁的一个状态 00 无锁 01 偏向锁 10 轻量级 11重
6.1. 什么情况下会数据不安全:
a . 数据共享 b. 多线程同时访问并改变该数据。使用场景:
修饰同步方法:锁当前实例对象 修饰静态方法:锁当前类的Class对象 修饰同步代码块: 锁括号里配置的对象java1.6以后,官方对synchronized做了大量的锁优化 提出了锁升级的概念
无锁 偏向锁 轻量级锁 轻量级锁考虑的是竞争锁对象的线程不多,而且线程持有锁的时间也不长的情景。 因为阻塞线程需要CPU从用户态转到内核态,代价较大,如果刚刚阻塞不久这个锁 就被释放了,那这个代价就有点得不偿失了,因此这个时候就干脆不阻塞 这个 线程,让它自旋这等待锁释放 重量级锁
juc同步工具
-
cas
compare and swap 比较再交换
cas是一种无锁算法,cas有3个操作数 内存值 预期值 要修改的值 当内存值和预期值相同时将内存值进行更改,否则什么都不做
原子类:AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference
原子数组:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray
原子属性更新器:AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater,
解决ABA问题:AtomicMarkableReference(通过boolean来反映中间有没有变过),AtomicStampedRefenrence(通过引入一个int来累加来反映中间有没有变过)
- aqs 基于voltaile+cas实现
AQS是一个同步器,设计模式是模板模式。 核心数据结构:双向链表 + state(锁状态) 底层操作:CAS
AQS中使用static记录锁的状态 0为无锁,1为加锁状态
```
/**
* The synchronization state.
*/
private volatile int state;
```
获取锁
```
/**
* tryAcquire 尝试获取锁
* acquireQueued 通过自旋判断当前队列节点是否可以获取锁
* addWaiter 通过自旋cas,将当前线程加入上面锁的双向链表中
*/
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
```
释放锁
释放锁就是对AQS中的状态值State进行修改。同时更新下一个链表中的线程等待节点。
-
voltaile
保证线程间的可见性(cpu缓存一直性协议:EMSI)
禁止指令重排
-
ReentrantLock
可重入互斥锁 基于AQS实现
必须要自己手动的开锁解锁
-
StampedLock
StampedLock类,在JDK1.8时引入,是对读写锁ReentrantReadWriteLock的增强,该类提供了一些功能,优化了读锁、写锁的访问,同时使读写锁之间可以互相转换,更细粒度控制并发
-
ReentrantReadWriteLock
- CountDownLatch
- CyclicBarrier
- Phaser
- Semaphore
-
Exchanger
用于两个线程之间数据的交换
-
LockSupper
-
ThreadLoal
做线程之间数据隔离的
-
ReentrantLock
-
StampedLock
-
ReentrantReadWriteLock
CountDownLatch 可用于项目的初始化工作 使用countdown减去完成的工作 await等待初始化的 CyclicBarrier 栅栏 多个线程到达某个点一起往下执行 phaser 分段式栅栏 Semaphore 信号量 Exchanger 两个现场间的数据交换 LockSupper 线程堵塞工具类
同步容器
Collection
List 有序 可重复
Vector 全部方法sychronized保证线程安全 写读都会加锁
ArrayList 线程不安全
CopyonWriteArrayList 写时复制 写时加锁 读不加 写效率低 用于读多写少
LinkedList
Set 无序 不可重复
HashSet
LinkedHashSet
Queue
主要方法
offer() 添加数据可以带时间 添加成功返回true 失败false
add() 添加元素 是否抛出异常
pick() 取数据 不会remove
poll() 取队列头元素 会remove掉取出的元素 取不到为null
ConcurrentLinkedQueue
PriorityQueque 会对队列进行排序 最小的排最前面
BlockingQuere 阻塞队列
LinkedBlockingQuere 使用链表实现的阻塞队列 最大为Integer最大值
put() 添加元素
take() 取出元素 如果队列空 了就会阻塞住
ArrayBlockingQuere 固定大小的队列
put满了就会阻塞
DelayQuere 用于按时间进行任务调度
按等待时间对队列进行排序 时间短先执行
take取
· SynchronousQuere 容量为0
put会阻塞等待消费者消费
take 消费
LinkedTransterQueue
transfer 添加 添加结束等待消费后再继续
Map 无序 以key value 存储 key不可重复
HashTable 线程安全
全部方法sychronized保证线程安全
HashMap 线程不安全
使用 Collection.Synchronized(new HashMap<String,Integer>()); 保证线程安全
ConcurrentHashMap 线程安全 无序 使用cas操作保证线程安全
ConcurrentSkipListMap 高并发且排序
基于跳表实现
TreeMap
使用了红黑树
线程池
对象引用类型
//强引用 就算内存溢出也不会回收
String str=new String();
//软引用 内存不够才回收,否则永远不会被回收 缓存
SoftReference<Integer> softReference = new SoftReference<Integer>(10);
System.out.println(softReference.get());
//弱引用 只要有垃圾回收就立刻回收
WeakReference<String> weakReference = new WeakReference<String> ("11");
//虚引用 回不回收都取不到 被回收后放入队列里 用于管理直接内存
ReferenceQueue<String> reference = new ReferenceQueue<String> ();
PhantomReference<String> pf=new PhantomReference("String",reference);