16、线程

多线程

一、概念

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以内偶数的和,最终将结果累加并输出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值