十三、多线程

一、多线程

1.线程与进程

进程(是软件):时机一个内存中运行的应用程序,每个进程都有一个独立的内存空间

线程:是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程最少有一个线程,线程实际上是在进程基础上的进一步划分,一个进程启动后,里面的若干执行路径又可以划分为若干个线程

2.线程调度

分时调度:所有线程轮流使用CPU的使用权,平均分配每个线程占用CUP的时间

抢占式调度:优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个(线程随机),java使用为抢占式调度

3.同步(线程安全)与异步(线程不安全)

同步:排队执行,效率低但是安全

异步:同时执行,效率高但是数据不安全

4.并发与并行

并发:指两个或多个事件在同一个时间段内发生

并行:指两个或多个事件在同一时刻发生(同时发生)

5.多线程技术

①.//创建一个类继承Thread 并实现抽象方法run() run里写入要同时运行的程序

public void MyThread extends Thread(){
run(){
//运行程序
}
}
//在main方法里要调用对象的start 方法来执行run方法里的程序
MyThread m = new MyThread();
m.start();

main方法是主线程 而run方法是分支线程 程序是同时运行但先后顺序不是固定的是 随机的

每个线程都拥有自己的栈空间,公用一分堆内存。由一个线程所调用的方法 那么这个方法也会调用在这个线程里面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6zEy53qr-1610471007401)(C:\Users\lenovo\Desktop\笔记\多线程图解.png)]

②.实现接口Runnable 实现抽象方法run()

public void class MyRunnable implents Runnable(){
run(){
//执行的任务
}
}
//main方法中
//创建一个任务对象
MyRunnable r = new MyRunnable();
//创建一个线程,并为其分配一个任务
Thread t = new Thread(r);
//执行
t.start();

③. 实现Runnable 与继承Thread相比有如下优势:

通过创建任务,然后给线程分配的方式来实现多线程,更适合多个线程同时执行相同任务的情况

可以避免单继承所带来的的局限性

java中只有单继承 但是有多实现

任务与线程本身是分离的,提高了程序的健壮性

后续学习的线程池技术,接受Runnable类型的任务,不接受Thread类型的线程

二、Thread类

1.构造方法

一参任务 二参任务名 通过getname可以获取任务名

2.方法

停止的方法 定义一个变量让线程时刻查看这个变量 然后return

sleep方法:休眠 传参1 毫秒 停止运行多少毫秒 参2 纳秒 多少毫秒纳秒

设置和获取线程名称: 在run方法中 调用Thread.currentThread().getName() 或setName() 默认名称是Thread-0

Thread.currentThread() 获取当前正在执行的线程 返回值类型是Thread

三、线程的休眠

Thread.sleep(1000); 相当于1秒钟运行一次 要进行trycatch处理

四、线程阻塞

所有消耗时间的操作和比较消耗时间的操作 比如接受用户输入 或读文件

五、线程中断

一个线程是一个独立的执行路径,他是否应该结束,应该由其自身决定

Thread t = new Thread();

方法 t.interrupt();//给线程添加中断标记 然后在catch块中添加return

在这里插入图片描述

六、守护线程

线程分为:守护线程和用户线程

用户线程:当一个进程不包含任何的存活的用户线程时,进程结束 手动设置的线程都是用户线程

守护线程:守护用户线程的 ,当最后一个用户线程结束时,所有守护线程自动死亡

设置守护线程一定要在start之前设置

线程对象.setDaemon(true);

七、线程安全问题

多个线程同时处理一个变量可能出现都进入while循环 循环条件是i>0 每循环一次i-- 但是最后结果打印i是小于0的

八、线程同步 (加锁机制)

方案1 同步代码块 隐式锁

格式:synchronized(锁对象){} java中任何东西都能是锁对象

要让所有线程都看同一把锁才能排队 不能每人一把 把if语句锁起来

在这里插入图片描述

方案2 同步方法 隐式锁

把要排队的部分编辑成方法 然后在方法中添加synchronized

锁机制是this 如果是静态修饰 就是类名.class

public synchronized void sale(){

}

这个方法只能是同一个对象

如果同步方法和同步代码块同时使用并且都是this对象 那么同步代码块被调用 同步方法别人也不能用

方案3 显示锁

Lock 子类 ReentrantLock

//创建一把锁 
Lock l = new ReentrantLock();
//锁 
l.lock();   
//解锁
l.unlock();

九、公平锁和非公平锁

意思就是:是不是解锁线程一起抢 谁抢到谁用

上面三种锁机制都是非公平锁

显示锁可以传参 Lock l = new ReentrantLock(true); 参数默认是false true就变成了公平锁

谁先来谁先得到这个锁

十、线程死锁

比如两个人在两个试衣间 a在1试衣间 b在2试衣间 a有一个方法让他去2试衣间 但是2试衣间有锁b在里面那么他要等b出来 而b有一个方法让他去1试衣间 但1试衣间有锁a在里面 他要等a出来 因此互等产生死锁

解决方法:在任何有可能导致锁产生的方法里,不要在调用另外一个方法让另外一个锁产生

十一、多线程通信问题

举例: 厨师 服务员 一个盘子 盘子空了厨师醒 服务员睡 盘子满了 服务员醒厨师睡

在盘子里定义一个boolean类型flag 如果flag等于true 厨师开始做饭 然后做完之后flag等于false 同时this.notifyAll(); 唤醒服务员 this.wait(); 自己睡眠 服务员那边是flag是false时进入 端完菜之后flag等于true this.notifyAll(); 唤醒厨师 this.wait(); 自己睡眠

服务员和厨师都要上锁 用同步方法

在这里插入图片描述

在这里插入图片描述

十二、线程的六种状态

new :线程刚创建出来 是new状态 还没启动

Runnable:正在执行的线程

Blocked:被阻塞等待的线程状态 排队

Waiting:无线等待另一个线程执行特定操作的状态 休眠

TimeWaiting:指定等待时间

Trminated :程序结束 线程死亡了 被终止了

无论哪种状态最终都会走到Trminated状态

十三、带返回值的线程Callable

Callable接口

实现方法 call() 运行线程方法

在这里插入图片描述

task.get() 是让主线程等子线程结束了在执行 收到返回值

task.isDone();判断这个线程是否执行完毕了

task.cancel(); 取消这个线程 有返回值true或false 一般false是这个线程已经结束了

十四、线程池 装线程的容器

创建线程 创建任务 执行任务 关闭线程

如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁的创建线程就会大大的降低系统的效率,因为创建和销毁线程需要时间,线程池就是一个容纳多个线程的容器,池中的线程可以反复使用,省去了频繁创建线程的操作

在这里插入图片描述

1.缓存线程池

流程:判断线程池是否存在空闲线程 存在测使用 不存在,则创建线程,并入线程池,然后使用

2.定长线程池

流程:判断线程池是否存在空闲线程 存在使用 不存在且线程池未满,则创建线程并入线程池,然后使用

不存在且线程池已满,则等待线程池存在空闲线程

3.单线程线程池

流程: 判断线程池的线程是否空闲 空闲则使用 不空闲则等待线程空闲再使用

4.周期性任务定长线程池

流程: 判断线程池是否存在空闲线程 存在使用 不存在且线程池未满,则创建线程并入线程池,然后使用

不存在且线程池已满,则等待线程池存在空闲线程

可以不是立即执行 可以定时执行

十五、缓存线程池

//创建线程池

ExecutorService s  =  Executors.newCachedThreadPool();

//向线程池中加入新的任务并执行

s.execute(new Runnable(){

public void run(){

syso(Thread.currentThread().getName()+"汗滴禾下土");

}

})

十六、定长线程池

ExecutorService s  =  Executors.newFixedThreadPool(2);// 给一个线程长度

s.execute(线程)

十七、单线程线程池

ExecutorService s  =  Executors.newSingleThreadExecutor();

s.execute(线程)

十八、周期定长线程池

ScheduledExecutorService s = Executors.newScheduledThreadPool(2);//传 线程数

//定时执行一次

//参数1  定时执行任务 参数二 时长数字  参数三 时长数字的时间单位 , TimeUnit的常量指定

s.schedule(任务线程,5,TimeUnit.SECONDS); // 5秒

//周期执行

//参数1 任务  参数2 延迟时长数字(第一次执行在什么时间以后)  参数3 周期时长数字(每隔多久执行一次)  参数4 时长数字单位

s.scheduleAtFixedRate(任务,51,TimeUnit.SECONDS)//五秒钟以后执行  每隔一秒执行一次

十九、Lambda表达式 函数式编程思想

实现前提就是这个接口只有一个方法

就是保留方法参数部分以及方法体

//冗余的Runnable代码


Thread t = new Thread(new Runnable(){

public void run(){

syso(Thread.currentThread().getName()+"汗滴禾下土");

}

});


//函数式编程思想


Thread t = new Thread( () -> syso(Thread.currentThread().getName()+"汗滴禾下土"));


//也可以


Thread t = new Thread( () -> {

syso(Thread.currentThread().getName()+"汗滴禾下土")});
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值