多线程
一、概念
1. 进程:在操作系统(os)中并发执行的多个任务。
并发的原理:CPU分时间片,宏观并行,微观串行。
2. 线程:在一个进程中,并发执行的多个程序逻辑。线程是进程执行的
单位。
3. 线程的组成部分
a) CPU : CPU分配时间片
b) 数据:堆空间共享,栈空间独立
1. 堆空间:对象 堆空间共享(每一个线程共享一个堆空间)
2. 栈空间: 局部变量 栈空间独立(每一个线程都有自己的栈空间)
c) 实现多线程的代码
二、实现线程的代码[掌握、重点]
1. 实现线程的方式1
a) 写一个类 实现Runnable(任务)接口 (任务类)
b) 实现run()方法
c) 创建任务对象
d) 创建线程对象
e) 启动线程
2. 实现线程的方式2
a) 继承Thread类
b) 覆盖run()方法
c) 创建线程对象(任务对象)
d) 启动线程
三、线程的状态图[理解]
1. static void sleep(long millis):休眠,让当前执行的线程进入到休眠
状态,放弃时间片。
2. void join(): 加入,让当前线程加入到其他线程,其他线程会进入到
无限期等待,等待当前线程执行完毕,其他线程才会执行。
3. static void yelid():让当前线程暂停,放弃时间片,参与到下一次时
间片的分配。
4. setDaemon(true):参数为true时,当前线程为守护线程
当其他线程执行完毕 而守护线程仍然没有执行完毕,也会进入到终止状态.
四、线程同步[重点 理解 应用]
问题:当多线程并发访问同一个临界资源时,如果破坏了原子操作,就
可能会导致数据结果的不一致(线程不安全)。
临界资源:多线程并发访问的同一个对象
原子操作:不可分割的一个整体,其顺序和步骤不能被打乱
解决方式:
每一个对象都有锁标记,只有拿到了对象的锁标记才能够进入到线程中
a) 同步代码块 synchronized
synchronized(o){//o 临界资源
//代码块 原子操作
}
1. 每一个对象都有一个互斥锁标记,这个锁标记可以附加给任何一个线程,当一个
线程拿到了对象的锁标记之后,其他线程拿不到,就会进入到阻塞状态。
2. 只有获取到对象锁标记的线程,才能进入到对对象加锁的同步代码块中。
3. 只有同步代码块中的内容都执行完毕之后才会释放对象的锁标记。
注意:sleep()不会释放锁标记
b)同步方法
synchronized可以修饰方法
语法: 修饰符 synchronized 返回值类型 方法名(){
//原子操作
}
面试: ArrayList和Vector的区别[理解]
Vector中的大部分都是synchronized修饰的,都是同步方法
ArrayList中的方法都是普通方法
五、线程通信[了解]
在Object中存在如下两个方法
wait():等待 会释放所有的锁标记,同时会进入到对象(临界资源锁标记)的等待队列
当调用了notify()时,此线程会进入到阻塞状态。
notify():通知 通知某一个线程从等待队列中出来,但是不会释放锁标记,只有将该
线程中所有的代码执行完毕之后才会释放锁标记。
notifyAll():通知 通知所有的线程从等待队列中出来。
注意:调用wait()|notify()|notifyAll()必须放在对o加锁的同步代码块
面试:sleep() 和wait()的区别
sleep(): 进入到有限期等待 会释放CPU时间片 但是不会释放锁标记
wait(): 进入到等待队列,会释放时间片和锁标记
六、线程池[重点]
1. 概念:线程容器,可设定线程分配的数量上限,将预先创建
线程对象存入池中,并重用线程池中的线程。
2. 好处:减少创建和销毁线程的次数,每个工作线程可用于执行多个任
务,只需将任务提交给线程,即可重复利用。
3. 常用的接口和类(所在包java.util.concurrent):
① Executor:线程池的顶级接口。
② ExecutorService:线程池接口,可通过submit(Runnable task) 提交任务代码
③ Executors工厂类:通过此类可以获得一个线程池。
I. 通过 newFixedThreadPool(int nThreads) 获取固定数量的线程池。参数:
指定线程池中线程的数量。
II.通过newCachedThreadPool() 获得动态数量的线程池,如不够则创建新
的,没有上限。
七、Callable接口
run()存在的问题:不能抛异常 没有返回值,为了解决以上问题,JDK1.5提供Callable接口
1. Callable接口: JDK5加入,与Runnable接口类似,实现之后也代表一
个线程任务。
2. 方法: V call() : 有泛型返回值、可以抛异常。
![Callable接口](E:\Corejava\课堂笔记及代码\day22_线程\笔记\Callable接口.png)思考:实现1+2+3+4+…..+100的和。要求一个线程实现1+2+3+….+50;另一个线程实现
51+52+53+….+100,最终将结果累加。
3. Future概念:异步计算的结果,ExecutorService.submit()所返回的状
态结果,当中包含了call()的返回值。
4. 方法:V get() //获得Future对象中call()的执行结果(根据Callable的泛
型决定V的具体类型)
练习:要求一个线程实现1~100以内奇数的和;另一个线程实现100~200以内偶数的和,最终将结果累加并输出。
4. 方法:V get() //获得Future对象中call()的执行结果(根据Callable的泛
型决定V的具体类型)
[外链图片转存中…(img-qVoOGuM4-1571966719370)]
练习:要求一个线程实现1~100以内奇数的和;另一个线程实现100~200以内偶数的和,最终将结果累加并输出。