JUC 类
hashMap是线程不安全的不能并发操作
hashTable是线程安全的有synchronized修饰,将锁直接加到put()上,效率低,相当于吧整个hash表锁住了,用在低并发情况下可以,独占锁
ConcurrentHashMap
ConcurrentHashMap 是线程安全的,采用锁分段机制,并没有将整个hash表锁住,但是jdk8之后没有使用分段锁(给每个位置创建一个锁标志对象),采用的是CAS思想+synchronized来实现
插入时检测hash表对应的位置是否是第一个节点,如果是,采用CAS机制(循环检测)向第一个位置插入数据
如果此位置已经有值,那么就以第一个Node对象为锁标志进行加锁,使用的是synchronized实现
public class HashMapDemo {
/*
HashMap是线程不安全的,不能并发操作的
ConcurrentModificationException 并发修改异常 遍历集合,并删除集合中的数据
Hashtable 是线程安全的 public synchronized V put(K key, V value)-->独占锁
锁直接加到了put方法上,锁粒度比较大,效率比较低
用在低并发情况下可以
Map<String,Integer> map = Collections.synchronizedMap(new HashMap<>());
ConcurrentHashMap
*/
public static void main(String[] args) {
ConcurrentHashMap<String,Integer> map = new ConcurrentHashMap<>();
//模拟多个线程对其操作
for (int i = 0; i < 20; i++) {
new Thread(
()->{
map.put(Thread.currentThread().getName(), new Random().nextInt());
System.out.println(map);
}
).start();
}
}
}
CopyOnWriteArrayList
读写完全分离 读操作完全不用加锁,读不影响数据
写操作加锁,写操作不影响读操作 两个线程同时添加会互斥
添加时先将原数组复制出一个副本
然后就将数据添加到副本中,不影响读操作
最后用副本替换原数组
CopyOnWriteArraySet
是一个不允许重复数据的
底层实现是CopyOnWriteArrayList,不能存储重复数据
辅助类CountDownLatch
使一个线程等待其他线程执行结束后再执行
相当于一个递减的线程计数器
先制定一个数量,当有一个线程结束后就减一,直到为0 关闭计数器 这样线程就执行了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wS5P0aFG-1642418593327)(C:\Users\云\AppData\Roaming\Typora\typora-user-images\1642401770485.png)]
辅助类 CyclicBarrier
让一组线程达到一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会开门
是一个加法计数器,当线程数量达到指定数量时才会开门放行
java中的锁
很多锁的名词,这些分类并不是全是指锁,有的指锁的特性,有的指锁的设计,
有的指锁的状态,下面总结的内容是对每个锁的名词进行一定的解释。
乐观锁/悲观锁
乐观锁:就是不加锁,认为并发的修改是没有问题的,例如CAS机制 设计一种无锁方式实现.适合读操作多
悲观锁: 认为并发操作会出现问题,需要通过加锁来保证安全.适合写操作多
可重入锁
Reentrant Lock
可以一定程度上避免死锁
当一个同步方法中,调用另一个和他使用同一把锁的方法时
在外层方法中即使没有释放的情况下,也可以进入到另一个同步方法
Reentrant Lock和synchronized都是可重入锁
eg:setA()和setB()方法用的是同一把锁,在进入setA方法后拿到了锁当调用setB方法,如果不是可重入锁,在setA()方法没有释放锁,setB()方法就不会被当前线程执行,当如果是可重入锁,setB()方法就可以顺利执行,不会造成死锁情况.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p1ee1woE-1642418593330)(C:\Users\云\AppData\Roaming\Typora\typora-user-images\1642417471732.png)]
读写锁(ReadWriteLock)
是具体的锁实现,读和写是两把锁,进行分离使用
分段锁
是一种加锁思想,并不是实际的锁实现,采用分段加锁,降低锁的粒度,从而提高效率
自旋锁(SpinLock)
不是一种锁实现,采用自旋(循环重试) 的方式进行尝试,获取执行权,不会让线程进入到阻塞的状态,适用于锁的时间较短的情况
CAS就是基于自旋锁实现
共享锁
可以被多个线程共享的锁
ReadWriteLock的读锁是共享的,多个线程可以同时读数据
独占锁
也称互斥锁,一次只能有一个线程获取锁
Reentrant Lock,synchronized,ReadWriteLock的写锁是独占锁
ReadWriteLock里面实现方式使用了同步对列,例如读线程获取资源,将标准state设置为已被使用,然后将其他的写线程加入到一个对列中等待.
AQS(AbstractQueuedSynchronizer)
维护一个对列,让等待的线程排队.
公平锁
就是会维护一个线程的等待对列,一次去执行线程
Reentrant Lock默认是非公平的,可以在创建时通过构造方法为其制定是公平锁还是非公平锁
非公平锁
没有对列,一旦锁释放,线程开始抢占,谁抢到执行权,谁先执行
锁的状态
无锁/偏向锁/轻量级锁/重量级锁
偏向锁:指的是一直只有一个线程在不断的获取锁,可以更方便的获取到锁
轻量级锁:当锁是偏向锁的时候,被另一个线程访问,偏向锁就会升级为轻量级锁,如果是轻量级锁那么等待线程不会进入阻塞状态,采用自旋方式,重新尝试获取锁,效率提高
重量级锁:当锁状态为轻量级锁时,如果有的线程自旋次数过多,或者有大量的线程访问,那么锁状态升级为重量级锁,此时未获得锁的线程不再自旋,进入阻塞状态
ReentrantLock
是类,只能修饰代码块 是显示锁,手动添加 手动释放
是类层面实现控制,采用CAS+AQS 是可重入锁,可以是公平锁,也可以不是公平锁
在类的内部维护了一个锁的状态,一旦有线程抢占到了,将状态改为1,其他的线程就进入到对列中等待锁的释放(当为公平锁时),锁一旦释放,那么就唤醒头结点,开始尝试去获得锁
synchronized
是可重入锁,非公平锁
是一个关键字,可以修饰代码块,也可以修饰方法
是隐式锁,可以自动获取释放锁
synchronized 实现加锁释放锁是指令级别的
有一个进入监视器进入+1 对象头锁标记被使用
执行任务
退出监视器 -1 当等于0时 对象头锁标记改为无锁