狂神说多线程笔记
bilibli视频地址:https://www.bilibili.com/video/BV1V4411p7EF/
1.基本概念
Process和Thread
程序:指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
进程:是执行程序的一次执行过程,是一个动态的概念。是系统资源分配的单位。
一个进程可以包含有多个线程(如视频中同时听到声音、看到图像,还可以看弹幕)
一个进程至少有一个线程,否则无存在的意义。
线程:CPU调度和执行的单位。
注意:很多多线程是模拟出来,真正的多线程是指有多个CPU,即多核,如服务器。如果是模拟出来的多线程,即在一个CPU的情况下,在同一个时间点,cpu只能执行一个代码,因为切换很快,所以就有同时执行的错觉。
2.核心概念
- 线程就是独立的执行路径;
- 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程;
- main()称为主线程,为系统的入口,用于执行整个程序;
- 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能认为干预的;
- 对同一份资源操作时,会存在资源抢夺问题,需要加入并发控制;
- 线程会带来额外的开销,如CPU调度时间,并发控制开销;
- 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
3.线程创建
1.继承Thread类,重写run方法**
a.创建Thread类
b.重写run()方法
c.调用start()开启线程
//创建线程方式一:继承Thread类,重写run()方法,调用start()开启线程
public class Test01 extends Thread{
@Override
public void run() {
//run方法线程体
for (int i = 0; i <20; i++) {
System.out.println("我在看代码");
}
}
public static void main(String[] args) {
//main线程,主线程
//创建一个线程对象
Test01 t= new Test01();
// t.run(); 调用run()方法,执行完run方法体再执行main方法体
//调用start()方法开启线程 同时执行
t.start();
for (int i = 0; i < 2000; i++) {
System.out.println(“我在学多线程"+i);
}
}
}
练习:网图下载
总结:线程开启不一定立即执行,由CPU调度执行
2.实现Runnable接口**
a.实现Runnable接口
b.重写run()方法
c.执行线程需要创建runnable接口实现类,调用start()方法
public static void main(String[] args) {
//创建一个线程对象
Test01 t= new Test01();
new Thread(t).start();
for (int i = 0; i < 2000; i++) {
System.out.println(“我在学多线程"+i);
}
}
练习:买火车票
public class TestTread implements Runnable {
//票数
private int ticketNums = 10;
@Override
public void run() {
while(true){
if(ticketNums<=0){
break;
}
//模拟延时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums-- +"票");
}
}
public static void main(String[] args) {
TestTread ticket = new TestTread();
new Thread(ticket,"小明").start();
new Thread(ticket,"老师").start();
new Thread(ticket,"黄牛").start();
}
}
案例:龟兔赛跑(待补)
小结:以上两者区别
-
继承Thread类:
- 子类继承Thread类具备多线程能力
- 启动线程:子类对象.start()
- 不建议使用:避免OOP单继承局限性
-
实现Runnable接口
- 实现Runnable接口具备多线程能力
- 启动线程:new Thread(子类对象).start()
- 推荐使用:避免单继承局限性,方便同一个对象被多个线程使
3.实现Callable接口
-
实现Calleble接口
-
重写call()方法
-
创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(线程数);
-
提交执行
Future<返回值类型> r = ser.submit(线程名);
-
获取结果
类型 res=r.get();
-
关闭服务
ser.shutdownNow();
总结:优点:1.可以定义返回值;2.能抛出异常
缺点:相比而言较为麻烦
4.静态代理
——多线程底层实现原理
例子: 真实角色:你; 代理角色:婚庆公司; 结婚:实现结婚接口
public class StaticProxy {
public static void main(String[] args) {
WeddingCompany company = new WeddingCompany(new You());
company.happyMarry();
}
}
interface Marry{
void happyMarry();
}
//真实角色
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("结婚了真开心!");
}
}
//代理角色,帮助你结婚
class WeddingCompany implements Marry{
private Marry target;
public WeddingCompany(Marry target){
this.target = target;
}
@Override
public void happyMarry() {
before();
this.target.happyMarry();
after();
}
private void after() {
System.out.println("结婚之后,收尾款");
}
private void before() {
System.out.println("结婚前,布置现场");
}
}
总结:真实对象和代理对象都要实现同一个接口,代理对象要代理真是角色
优点:代理对象可以做很多真实对象不能做的事情
真实对象专注自己的事情
结合线程来看:
new Thread(t).start();
new WeddingCompany(new You()).happyMarry();
Runnable ——> Marry 接口
Thread ---->WeddingCompany 即代理
t ——> new You() 目标对象(真实角色)
5.Lambda表达式
- 实质属于函数式编程的概念
1.作用
- 避免匿名内部类定义过多
- 使代码看起来简介
- 简化代码,只留下核心逻辑
2.函数式接口
定义:任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口
public interface Runnable{
public abstract void run();
}
对于函数式接口,我们可以通过lambda表达式来创建该接口的对象
3.lambda简单推导
package com.lmr.practice;
/**
* 推导Lambda表达式
* @author DELL
*
*/
public class TestLambda {
//3.静态内部类
static class Like2 implements Ilike{
@Override
public void lambda() {
System.out.println("i like lambda2");
}
}
public static void main(String[] args) {
Ilike like = new Like();
like.lambda();
like = new Like2();
like.lambda();
//4.局部内部类
class Like3 implements Ilike{
@Override
public void lambda() {
System.out.println("i like lambda4");
}
}
like = new Like3();
like.lambda();
//5.匿名内部类
like = new Ilike() {
@Override
public void lambda() {
System.out.println("i like lambda5");
}
};
like.lambda();
//6.用lambda简化
like = ()->{
System.out.println("i like lambda5");
};
like.lambda();
}
}
//1.定义一个函数式接口
interface Ilike{
void lambda();
}
//2.实现类
class Like implements Ilike{
@Override
public void lambda() {
System.out.println("i like lambda");
}
}
package com.lmr.practice;
public class TestLambda2 {
public static void main(String[] args) {
ILove love = null