今天学的赶紧记录,之前没赶的进度之后搞。。
目录
多线程
1.cpu基础知识
cpu:中央处理器→1.运算器 作用运算
2.控制器 负责发出cpu每条指令所需信息
3.寄存器 保存运算或指令的一些临时文件
进程:1.cpu从硬盘中读取一段程序到内存中,该执行程序的实例叫进程。
2.一个程序如果被cpu多次读取到内存中,则变成多个独立进程。
线程:线程是程序执行的最小单位,在进程中可以有多个不同的线程同时执行。(同一个过程中,更好并行处理)
线程运行在cpu之上
总结:进程是资源分配最小单位,线程是程序执行最小单位。
Cpu密集型/IO密集型
Cpu密集型:长时间占用cpu;例如: 视频剪辑
IO密集型 :cpu计算时间短 访问外接设备时间长
Input/output
1.1为什么在进程中还需要线程呢?
同一个应用程序中(进程),更好并行处理。
1.2CPU调度算法原理
1. 先来先服务 缺点如果最先来执行的线程 是CPU密集型 这样话可能会一直
无法继续执行其他的线程。
2. 最短作业法 谁的计算时间短,谁先来执行。
3. 优先级调度算法 根据重要性将进程分成4个优先级
优先级4 进程D负责画面----
优先级3 进程B和进程C接受用户的指令 重要
优先级2 后台处理器 次要
优先级1
2.多线程效率问题与底层原理
1.为什么使用多线程?
采用多线程形式执行代码,目的就是为了提高程序效率。
2.串行/并行区别?
串行 单线程执行,代码效率低代码从上到下。
并行 多线程并行一起执行,效率高。
3.使用多线程一定效率高?
不一定,cpu调度的算法,先把前一个任务的cpu上下文(也就是cpu寄存器和程序计数器:从汇编语言底层
角度,不是java源代码角度,Java源代码一句可能汇编会有四句)保存起来,然后加载新任务的上下文到这些
寄存器和程序计数器,最后在跳转到程序计数器所指的新位置,运行新任务。
4.什么是上下文?
所谓多线程,在线程数远大于cpu内核数是,所有线程被cpu调度时间片所调度,在短时间内多次在运行状
态和就绪状态之间切换。(如果生产环境中开启几百个或几千个线程,而我们服务器内核数一般8、16、32 ,
这么多线程都会在cpu上做上下文切换,导致效率低下)
5.一般会设置线程池:8内核的cpu可以限定最多八个线程,减少cpu做上下文切换。
6.多线程同步/异步的区别?
同步:代码从上到下运行
异步:单独分支运行,相互之间没有影响
3.多线程创建方式
①继承Thread
new Thread(thread01).start();
②实现Runnable类
Thread abc = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("abc");
}
});
abc.start();
③使用匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("abc");
}
}).start();
④使用lamda表达式
new Thread(() -> System.out.println("abc")).start();
⑤使用callable和Future创建
//先创建一个ThreadCallable类
ThreadCallable threadCallable = new ThreadCallable();
FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(threadCallable);
Thread thread = new Thread(integerFutureTask);
thread.start();
⑥使用线程池例如Executor
ExecutorService executorService = Executor.newCachedThreadpod();
executorService.execute(() -> System.out.println("") );
⑦spring @Async
4.线程安全性问题
1.线程安全问题定义
当多个线程共享一个全局变量(放在堆内存中),在做写操作时,可能会受到其他线程干扰,发生线程安全性
问题。
2.如何解决线程安全性问题?/如何实现线程同步?
在同一JVM中,多个线程需要竞争锁资源,最终只有一个线程能够获取锁,多个线程同时抢同一把锁,谁能获
取到锁,谁就可以被执行,如果一直没有获取锁成功,中间就要经历锁的升级,如果一直没有获得到锁,该线
程就一直会阻塞等待。(核心思想:同JVM中当多个线程共享同一个全局变量时,将可能会发生线程安全性的
代码上锁,保证只有拿到锁的线程才可以执行,没有拿到锁的线程不可以执行,需要阻止。)
3.JUC并发编程:重入锁、悲观锁、乐观锁、公平锁、非公平锁(synchronized锁)
4.代码加锁的缺点:可能会影响到程序的执行效率。
5.synchronized基本用法
1.修饰代码块
synchronized(对象锁){
需要保证线程安全的代码。
}
2.修饰实例方法(this锁)
3.修饰静态方法(类名.class锁)
tips:1.多线程情况下,需要的是同一个对象锁。
2.注意synchronized锁的死锁问题,锁嵌套会引发死锁问题。
6.如何保证线程同步问题
如何保证线程同步问题(如何保证线程安全性问题)?(具体操作)
1.使用synchronized锁,jdk1.6锁的升级过程(偏量锁→轻量级锁→重量级锁)
2.使用Lock锁,需要自己完成锁的升级过程,底层基于AQS+CAS实现。
3.使用ThreadLocal,需要注意内存泄漏问题
4.原子类CAS 非阻塞式
7.wait、notify注意事项
this.wait(); 释放锁资源,同时当前线程会阻塞。
this.notify(); 竞争锁资源,竞争到锁的线程继续运行。(只是让线程重新拥有竞争锁资源的资格,并不是直接拥有锁)
以上两个方法需要结合synchronized 锁,需要放在synchronized锁同步代码块中。
join():
1.join() 底层用wait() and notify()封装的。
2.t.join()方法只会使调用t.join()的线程进入等待池并等待t执行完毕后才会被自动唤醒(唤醒的过程封装
在Java虚拟机里,并不在join源代码里),并不影响同一时刻处在运行状态的其他线程。
8.多线程的七种执行状态以及用户线程和守护线程
8.1多线程的七种执行状态
多线程的七种执行状态
初始化状态
就绪状态
运行状态
死亡状态
阻塞状态
超时等待
等待状态
Thread.sleep() 防止死循环导致cpu占用过高
8.2用户线程和守护线程
用户线程和守护线程
1.java中线程分为两种:①用户线程Thread.setDaemon(false),默认用户线程
②守护线程Thread.setDaemon(true)
2.①守护线程是依赖于用户现场,用户线程退出了,守护线程也就会退出,典型的守护线程例如垃圾回收线程。
②用户现场是独立存在的,不会因为其他线程退出而退出。
9.停止线程和多线程优先级
9.1停止线程
1.如何安全的停止一个线程
interrupt 中断 阻塞或者正在运行的线程
2.多线程yield
主动释放cpu
1.多线程yield会让线程从运行状态进入到就绪状态,然后调度执行其他线程。
2.具体实现依赖于底层操作系统的任务调度器
9.2多线程优先级
多线程优先级
1.在java语言中,每个线程都有优先级,当线程调度器有机会选择新的线程时,现场的优先级越高,越有可
能被选中执行,线程的优先级可以设置为1-10。
tips:Orcle 为Linux 提供的java虚拟机,线程的优先级1将被忽略,即所有线程具有相同的优先级(不要
过度依赖优先级)
2.线程的优先级用数字来表示,MIN_PRIORITY 到 MAX_PRIORITY 就是1-10,默认的NORM_PRIORITY = 5
3.如果cpu很繁忙,优先级越高的线程能获得更多的时间片,但是cpu空闲时,设置的优先级几乎没什么用。
10.join/wait与sleep之间的区别
sleep(long) 睡眠期间不释放锁
join(long) 先执行调用join方法的线程,等待中释放锁,底层基于wait()封装
wait(long) 在等待中释放锁,需在synchronized锁中