即便是单核处理器也支持多线程执行代码,CPU 经过给每一个线程分配 CPU 时间片来执行任务,当前任务执行一个时间片后会切换到下一个任务,因此 CPU 经过不停的切换线程执行。java
并发执行若是没有达到必定的数量级,速度反而会比串行执行要慢。这是由于线程有建立和上下文切换的开销。程序员
如何减小线程建立和上下文切换的开销?(“vmstat 1” 的 cs 参数,查看线程切换的次数)算法
如何避免死锁?数据库
在Java SE 1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁(也称互斥锁)状态,这几个状态会随着竞争状况逐渐升级。锁能够升级但不能降级,这种策略的目的是为了提升得到锁和释放锁的效率。有意思的是除了偏向锁,JVM 实现锁的方式都用了循环 CAS,即当一个线程想进入同步块的时候使用循环 CAS 的方式来获取锁,当它退出同步块的时候使用循环 CAS 释放锁。
若是只有一个线程进入同步代码块,那么它首先会得到“偏向锁”;当存在线程间竞争的时候,“偏向锁”会撤销,从而使用“轻量级锁”;当线程经过自旋方式始终获取不到“轻量级锁”时(获取锁的线程执行时间过长等缘由),那么“轻量级锁”会膨胀成“重量级锁”。编程
JMM(Java 内存模型)采用共享内存模型,经过控制主内存(Main Memory)与每一个线程的本地内存(Local Memory)之间的交互,来为 Java 程序员提供内存可见性保证。缓存
从 Java 源代码到最终实际执行的指令序列,会分别经历“编译器优化的重排序”、“指令级并行的重排序”、“内存系统的重排序”,前一个属于编译器重排序,后两个属于处理器重排序,这些重排序会致使多线程程序出现内存可见性问题。为了保证内存可见性,Java 编译器在生成指令序列的适当位置会插入内存屏障指令来禁止特定类型的处理器重排序。JMM 把内存屏障分为四类:
服务器
happens-before 是 JMM 最核心的概念。happens-before 规则对应于一个或多个编译器和处理器重排序规则,JMM 经过 happens-before 规则隐藏了复杂的重排序规则以及这些规则的具体实现,而程序员在 happens-before 规则上编程,从而保证内存可见性。多线程
顺序一致性内存模型是一个理论参考模型,JMM 和处理器内存模型在设计时一般会以顺序一致性内存模型为参照。并发
顺序一致性模型、JMM、处理器内存模型,内存模型设计由强变弱,由于越是追求性能,内存模型就会设计的越弱,以此减小内存模型对它们的束缚。app
理解 volatile 特性的一个好方法是把对 volatile 变量的单个读/写,当作是使用同一个锁对这些单个读/写操做作了同步。简而言之,volatile 变量自身具备下列特性:
volatile 关键字如何保证可见性?volatile 的内存语义?
volatile 关键字如何保证有序性?
为何 JDK 文档说 CAS 同时具备 volatile 读和 volatile 写的内存语义?
Synchonized 关键字的原理?JVM 基于进入和退出 Monitor 对象来实现方法同步和代码块同步,但二者的实现细节不同。代码块同步是使用 monitorenter 和 monitorexit 指令实现的,而方法同步是使用另一种方式实现的,细节在 JVM 规范里并无详细说明。
锁的释放和获取的内存语义?
对于 final 变量,编译器和处理器要遵照两个重排序规则(对象引用不在构造函数中“溢出”的状况下):
final 变量的内存语义?
在构造函数内部,不能让这个被构造对象的引用为其余线程所见,也就是对象引用不能在构造函数中“溢出”。由于 JMM 没法保证在构造函数中“对变量的写”和“被构造对象的引用” 这二者之间是否会被重排序。
jps 和 jstack 命令?
jstack 18023 > /home/wwwroot/dump18023
grep java.lang.Thread.State dump18023 | awk '{print $2$3$4$5}' | sort | uniq -c
可使用ODPS、Hadoop 或者本身搭建服务器集群来解决硬件资源限制的问题。
一个对象的引用占 4 个字节。