和进程区别:
特指Java虚拟机的状态,而不是操作系统中的
按次序完成某个任务,如下的命令都是在多个线程的情况下调用才有意义。
join B线程中调用A线程的join,需要等待A线程结束之后再继续B的语句,B会放到阻塞队列。
Object的方法
Condition的方法
BlockingQueue 使用阻塞队列进行通信
sleep和wait的区别
| wait | sleep | |
|---|---|---|
| 同步 | 只能在同步上下文中使用 | 任何地方都可以调用 |
| 作用对象 | 定义在Object中,作用于对象 | 定义在Thread中,作用于当前线程 |
| 释放锁资源 | 是 | 否 |
| 唤醒条件 | 其他线程使用notify或者notifyAll | 超时或者调用interrupt方法 |
| 方法属性 | 实例方法 | 静态方法 |
多个线程不管以何种方式访问某个类,并且在主调代码中不需要进行同步,都能表现正确的行为。
对于集合类型,可以使用 Collections.unmodifiableXXX() 方法来获取一个不可变的集合。其对原始集合进行拷贝,需要对其修改的方法都会抛出异常。
使用AQS实现
使用FairSync和NonfairSync来实现公平锁和非公平锁。

| synchronized | ReentrantLock | |
|---|---|---|
| 实现 | JVM | JDK |
| 性能 | 新版本进行自选锁等优化,性能大致和Reentrantlock相同 | 差不多 |
| 等待可中断(线程放弃等待) | 不可中断 | 可中断 |
| 公平锁(按申请时间顺序依次获取) | 非公平 | 默认非公平,也可公平 |
| 绑定多个条件 | 否 | 可以绑定多个Condition对象 |
| 出现异常是否释放锁 | 是 | 否 |
| 是否可知获得锁成功 | 否 | 是 |
| 使用选择 | JVM原生支持,会保证锁的释放,优先选择 | * 公平锁 * 灵活使用 * interrupt中断 * 实现线程精确唤醒 |
如果一个方法本来就不涉及共享数据,那它自然就无须任何同步措施去保证正确性。
栈封闭 多个线程访问同一个方法的局部变量时,不会出现线程安全问题,因为局部变量存储在虚拟机栈中,属于线程私有的。
线程本地存储(Thread Local Storage)
由于Map底层数据结构可能存在内存泄露的情况,尽可能每次使用后手动调用remove
可重入代码
优化主要是JVM实现的。
锁的四种状态:
其他措施:
对象头的mark word存放什么
添加内存屏障,lock指令
处理器上的寄存器的读写速度比内存快好几个数量级,为了解决这种速度矛盾,在他们之间增加了高速缓存,并使用一致性协议解决缓存之间数据不一致问题。
所有变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线程使用的变量的主内存的副本拷贝。线程只能操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成(Load和Store)。
不需要控制就能让一个操作先于另一个操作完成。
JDK8新增的用于并发环境都计数器,高并发情况下,代替AtomicLong,因为其用锁分段实现,并发计数时不同线程可以在不同计数单元进行计数,最后和base相加得到最终结果,减少线程竞争,提高并发效率,但是可能会造成统计数据有所误差。高并发优先使用LongAddr,但是如果需要准确数值,如序号生成,全局唯一的AtomicLong才是正确选择。
保证多线程下不会出现超卖等情况。
AtomicInteger
AtomicBoolean
AtomicLong
使用方式和基本类型基本一致,只是会多个索引位,适用于管理一批原子变量。
AtomicIntegerArray 整型数组的某个元素
AtomicLongArray 长整型数组的某个元素
构造传入数组。
需要原子引用类型变量的话使用。
原子更新引用类型
原子更新引用类型里的字段
原子更新带有标记位的引用类型。
使用需要两步操作
其复用原理是使得线程和任务解耦,不再是一对一关系,让每个线程执行一个循环任务,不断判断是否有任务需要被执行,有就直接run。
推荐使用该方式来创建线程池,可以控制核心线程数、最大线程数等信息。
corePoolSize 核心线程数
maximumPoolSize 最大线程数
keepAliveTime 超过核心线程数后的线程存活时间
unit 时间单位
workQueue 使用到的阻塞队列
threadFactory 线程工厂,提供创建新线程的功能
handler 超过最大线程数的拒绝策略
提交不需要返回值的任务,无法判断任务是否被线程池执行与否。
用于提交有返回值的任务,返回Future类型对象,通过该对象判断是否执行成功,用get返回值
控制线程是否能够进入某一同步代码区,相比synchronized,Semaphore可以指定多个进入,从测试来看,默认采用非公平模式(返回乱序)。
允许一个或者多个线程一直等待,直到其他线程执行完之后再执行。
实现线程间的计数等待,可以循环使用,一轮集体结束执行下一轮。
阻塞队列可以保留超出长度的任务,其原理是阻塞超出的线程,让其成为wait状态,释放CPU资源,由其自动阻塞、唤醒。
使用int变量表示同步状态,内置FIFO队列来完成获取资源线程的排队工作。
每个元素有过期时间,优先级队列,拿元素只拿过期元素。
任务分割 执行任务合并结果
ForkJoinTask ,如果使用该框架,首先需要创建一个ForkJoin任务,该类提供了在任务中执行fork和join机制,一般继承子类:
ForkJoinPool ForkJoinTask需要通过ForkJoinPool来执行。
主要用于并行计算中,和 MapReduce 原理类似,都是把大的计算任务拆分成多个小任务并行计算。
ForkJoin 使用 ForkJoinPool 来启动,它是一个特殊的线程池,线程数量取决于 CPU 核数。
public class ForkJoinPool extends AbstractExecutorService
ForkJoinPool 实现了工作窃取算法来提高 CPU 的利用率。每个线程都维护了一个双端队列,用来存储需要执行的任务。工作窃取算法允许空闲的线程从其它线程的双端队列中窃取一个任务来执行。窃取的任务必须是最晚的任务,避免和队列所属线程发生竞争。例如下图中,Thread2 从 Thread1 的队列中拿出最晚的 Task1 任务,Thread1 会拿出 Task2 来执行,这样就避免发生竞争。但是如果队列中只有一个任务时还是会发生竞争。