一、并发与并行
1.并发
早期计算机CPU是单核的,为了提高CPU的利用率,减少等待时间,使用到了并发工作的理论
并发就是将CPU资源合理分配给多个任务,当一个任务执行I/O操作时,转去执行其他任务
2.并行
针对多核CPU,有了并行的工作方法,并行就是多核CPU同时独立执行一个任务,而且多个任务互不干扰
二、进程与线程
1.进程
指系统中正在运行的一个应用程序的一个实例
2.线程
一个进程中存在多个线程,是程序执行的最小单位
线程的状态:
- NEW(新建)
线程对象已经创建,但未运行 - RUNNABLE(可运行)
线程已启动,准备运行 - BLOCKED(阻塞)
线程试图获取已被持有的锁,会被阻塞直到被释放 - WAITING(等待)
线程无限期处于等待状态,等待其他线程执行特定动作 - TIMED_WAIING(限时等待)
线程处于有限期等待状态,等待其他线程执行特定动作或者时间间隔 - TERMINATED(终止)
线程执行完或因异常被终止
三、wait和sleep的区别
1.使用方式
wait() 方法属于Object类
sleep() 方法属于Thread方法,静态方法
2.对锁的影响
wait() 方法会释放锁
sleep() 方法不会释放锁
3.唤醒方式
wait() 方法需要手动唤醒 notify() 或 notifyAll()
sleep() 方法自动唤醒
四、JUC中的原子类
1.基本类型原子类
1)Atomiclnteger 整型原子类
主要方法:
- get() :获取当前值
- set(int newValue) :设置当前值
- incrementAndGet() :自增当前值并返回结果
- decrementAndGet() :自减当前值并返回结果
- getAndIncrement() :自增当前值并返回原值
- getAndDecrement() :自减当前值并返回原值
- addAndGet(int delta) :当前值加上指定值并返回结果
- getAndAdd(int delta) :当前值加上指定值并返回原值
- compareAndSet(int expect, int updater) :如果当前值为预期值,则将当前值设置为更新值,否则返回false
2)AtomicLong 长整型原子类
主要方法与AtomicInteger类似,处理的是64位长整型值
3)AtomicReference 引用类型原子类
可以存储任何类型对象,可以用来创建复杂的原子数据结构,如原子对列,栈等
4)AtomicBoolean 布尔型原子类
提供了线程安全的布尔值更新
2.原子数组
AtomicIntegerArray 整型原子数组
AtomicLongArray 长整型原子数组
AtomicReferenceArray 引用类型原子数组
常用方法
- get(index) :返回指定索引处的值
- compareAndSet(index, expectedValue, newValue) :如果指定索引处的值为预期值,则设置为给定的新值
- getAndIncrement(index) :指定索引处自增返回旧值
- getAndDecrement(index): 指定索引处的值自减返回旧值。
- getAndAdd(index, delta): 指定索引处的值加上给定的增量并返回旧值。
- addAndGet(index, delta): 指定索引处的值加上给定的增量并返回新值
3.计数器(LongAdder)
主要用于需要的频繁更新和读取的大量数据并发场景,使用无锁技术以及基于分段的技术器实现高性能的原子操作,性能比AtomicLong高
方法:
- add(long x) :增加指定值
- increment() :自增
- decrement() :自减
- reset() :重置计数器
- sum() :获取当前总和
五、JUC包中的辅助类
1.CountDownLatch
允许一个或多个线程等待其他线程完成某些操作,当计数器的值减为零时,所有等待的线程被释放
主要方法:
- 构造函数CountDownLatch(int coun):构造一个带有指定技术的CountDownLatch实例
- countDown() :每次调用方法计数减一
- await() :阻塞当前线程,直到计数为0或超时
2.CyclicBarrier 同步辅助类
可以让多个线程互相等待,直到所有线程到达屏障点
主要方法:
- 构造方法:
- CyclicBarrier(int parties): 创建一个新的 CyclicBarrier,参数 parties 指的是需要等待的线程数量。
- CyclicBarrier(int parties, Runnable barrierAction): 与第一个构造函数类似,但当所有线程都到达屏障时,会有一个额外的Runnable 任务被执行
- 成员方法
- await():阻塞当前线程,直到所有参与的线程都调用了此方法。
- reset(): 重置屏障,取消所有正在等待的线程。
- getParties(): 返回屏障的参与者数量。
- isBroken(): 返回一个布尔值表示屏障是否已被中断或超时。
3.Semaphore 信号量
用于控制同时访问某个资源的线程数量。它的本质是一个“共享锁“。
主要方法:
- 构造函数:
- Semaphore(int permits):创建一个具有给定数量许可的 Semaphore。
- Semaphore(int permits, boolean fair):创建一个具有给定数量许可的 Semaphore,并且可以选择是否公平分配许可。
- 获取许可:
- acquire():等待直到获取一个许可,如果所有许可都被占用,则线程将被阻塞。
- acquireUninterruptibly():等待直到获取一个许可,即使线程被中断也不会抛出异常。
- tryAcquire():尝试获取一个许可,如果许可可用则立即返回 true,否则返回 false。
- tryAcquire(long timeout, TimeUnit unit):尝试在给定时间内获取一个许可,如果在超时时间内许可可用则立即返回 true,否则返回 false。
- 释放许可:
- release():释放一个许可,增加可用的许可数量。
- 查询状态:
- availablePermits():返回当前可用的许可数量。
- getQueueLength():返回等待获取许可的线程数量。
- hasQueuedThreads():返回是否有线程正在等待获取许可。
- drainPermits():获取并消耗所有可用的许可。
六、ConcurrentHashMap
ConcurrentHashMap是Java中一个线程安全的HashMap实现,它被设计用于在多线程环境中高效地存储键值对。
在ConcurrentHashMap中,key和value都不允许为null
主要方法:
- put(key, value):插入或更新键值对。
- get(key):获取键对应的值。
- remove(key):删除指定键的映射。
- containsKey(key):检查是否存在指定的键。
- forEach(BiConsumer):遍历所有键值对。
- computeIfAbsent(key, mappingFunction):如果键不存在,则计算并放入新值。