第一章:
1.1上下文切换:cpu切换下一个进程前,需要保留当前线程的执行状态,下次切换到此线程,可以再加载这个任务的状态
1.1.1面试点?单线程和多线程哪个快?
上下文切换
上下文切换:cpu切换下一个进程前,需要保留当前线程的执行状态,下次切换到此线程,可以再加载这个任务的状态
任务从保存到再加载的过程就是一次上下文切换。上下文
切换也会影响多线程的执行速度
表1-1有问题,测试是采用多核cpu测量的
串行就是单线程
单核情况下,如果没有cpu浪费,那么单线程是最快的
1.1.2面试点?性能测试工具?
1.使用Lmbench3 可以测量上下文切换的时长。
2.使用vmstat可以测量上下文切换的次数。
上下文切换时间?上下文每次切换1毫秒左右
1.1.3如何减少上下文切换?(面试点)
减少上下文切换的方法有无锁并发编程、CAS算法、使用最少线程和使用协程。
协程的概念:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换
1.1.4减少上下文切换实战
jstack:jvm查看堆栈信息的指令
dump:把当前的信息导入到某个文件中
第一步 :用jstack命令dump线程信息,看看pid为3117的进程里的线程都在做什么
sudo -u admin /opt/ifeve/java/bin/jstack 31177 > /home/tengfei.fangtf/dump17
sudo -u admin 管理员身份运行
opt/ifeve/java/bin/jstack 31177 jstack指令查看31177进程 31177是进程id
JBOSS类似于tomcat
java.lang.Thread.State 表示线程状态
1.2死锁
死锁的概念:线程彼此都锁住一个,又都等待对方释放
死锁代码案例:
//这段代码会引起死锁,使线程t1和线程t2互相等待对方释放锁。
//cpu会随时切换线程,只要是加锁了,此线程被切换,这个锁还是存在的,只有当此线程加的锁内的代码
//块执行完,才释放锁
//waiting to lock表示等待锁被释放 locked <7fb2f3ef8> 表示锁住了
public class SiSuo {
private static String A = "A"; //在此处不能直接对变量进行加锁
private static String B = "B";
public static void main(String[] args) {
new SiSuo().deadLock();
}
private void deadLock() {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized(A) {
try { Thread.currentThread().sleep(2000);
} catch(InterruptedException e) {
e.printStackTrace();
}
synchronized(B) {
System.out.println("1");
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (B) {
synchronized(A) {
System.out.println("2");
}
}
}
});
t1.start(); //此处表示t1线程先进去就绪态,t1线程先执行的几率大
t2.start();
}
}
面试点:避免死锁的几个常见方法
1.避免一个线程同时获取多个锁。
2.避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
3.尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。
4.对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况
1.3资源限制的挑战
第二章 JAVA并发机制的底层实现原理
Java代码在编译后会变成Java字节码(.class文件),字节码被类加载器(JRE)加载到JVM里,JVM执行字节
码,最终需要转化为汇编指令(汇编和c)在CPU上执行,Java中所使用的并发机制依赖于JVM的实现和
CPU的指令
2.1volatile的应用
面试点:synchronized和volatile的区别?
synchronized是读写锁 volatile在多处理器开发中保证了共享变量的“可见性”,当一个线程
修改一个共享变量时,另外一个线程能读到这个修改的值
共享变量:线程共同操作某一个变量,大多是引用类型
2.1.1
排他锁:在一个线程执行时另一个线程不能执行
cpu的术语定义
1.内存屏障:就是编写者给某块内存加一块标记,当读取它的时候会不让读取
2.原子操作:如果操作不能原子地执行,则要么执行完所有步骤,要么一步也不执行,不可能只执行所有步骤的一个子集
3.缓存:缓存就是存储在一个距离更近的地方,缓存存储访问频率比较高的数据
4.缓存淘汰策略LRU算法也是必考的,页面置换算法
5.缓存命中:缓存存储的是访问器访问频率比较高的数据,处理器读取数据时先从缓存中查找,如果找到了,就不再
从内存中读取,这称为缓存命中
6.写命中:cpu修改完数据先查看缓存中有没有这个数据,如果有就把写回结果然回到缓存中,而不是写回内存,
这个操作被成为写命中(多核cpu直接写回内存占用总线)
7.写缺失:缓存往内存返回数据时,发现内存中此数据地址缺失,不能成功地返回数据,这称为写缺失