进程:是程序的基本执行实体
理解:每一个运行的软件就是一个进程
线程:是操做系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位
理解:应用软件中互相独立,可以同时运行的功能
为什么要有多线程?
有了多线程就可以让程序同时做多件事情
可以提高程序的运行效率
多线程的应用场景
1.并发
同一时刻,有多个指令在单个cpu上交替
执行
2.并行
同一时刻,有多个指令在多个cpu上同时
执行
并发和并行是有可能都在发生的
继承Thread类的方式
实现Runnable接口的方式
细节:getName()是Thread类中的方法,所以想要调用,则
需要获取到当前线程的对象,然后用这个对象去调用
利用Callable接口和Future接口的方式
**特点:**可以获取到多线程运行的结果
多线程三种实现方式对比
Thread类中常见的成员方法
细节:
1.如果我们没有给线程设置名字,线程也是有默认名字
的
格式:Thread-x
(x是序号,从0开始)
2.如果我们要给线程设置名字,可以用set方法
进行设置,也可以用构造方法
进行设置
细节:
1.当JVM虚拟机启动之后,会自动的启动多条线程,其中有一条线程就叫做main线程
它的作用就是调用main方法
,并执行里面的代码
2.哪条线程执行到sleep(),那么哪条线程就停留对应的时间
3.参数:时间,单位:毫秒
在计算机当中,线程的调度
有两种
第一种,抢占式调度
所谓抢占式调度,就是多个线程在抢夺cpu的执行权
cpu在什么时候执行哪条线程是不确定的,执行多长时间也是不确定的,体现随机性
第二种方式,非抢占式调度
所有的线程轮流的执行
在java
中,采用的是第一种
,抢占式调度
优先级越大,线程抢到cpu的概率就越大
优先级最低:1
最高:10
默认:5
细节:
当其他的非守护线程执行完毕之后,守护线程会陆续
结束
守护线程的应用场景:
比如,聊天窗口,既可以聊天,也可以发文件
把聊天
看成一个线程,发文件
看成另一个线程
此时,如果把聊天窗口关掉,那么发文件线程也就没有存在的必要了
所以,就可以把发文件线程设置为守护线程
尽可能的让出cpu
线程的生命周期
买票引发的安全问题
线程执行时,有随机性
同步代码块
把操做共享数据
的代码锁起来
格式:
特点:
锁对象是任意的对象,但是要保证锁对象是唯一
的
static Object obj = new Object();
同步代码块的两个细节
锁对象一定是唯一的,一般用字节码文件对象:类名.class
synchronized一定要写在循环的里面
说明:如果把synchronized写在了循环的外面,那么其他线程将没有机会去执行任务,任务都被线程一执行完了
同步方法
如果我们想把一个方法里面的所有代码都锁起来,那么就没有必要使用同步代码块了
可以把synchronized直接加到方法上,那么这个方法就是同步方法
格式:
修饰符 synchronized 返回值类型 方法名(方法参数){}
特点:
不能
自己指定
非静态
的,它的锁对象是this
,就是当前方法的调用者静态的
,它的锁对象是当前类的字节码文件
对象写同步方法的技巧:
先写同步代码块,然后把同步代码块抽取成一个方法
lock锁
在JDK5
以后提供了一个新的锁对象Lock
它的实现比synchronized有更广泛的锁定操做
它提供了两个方法:
void lock():获得锁
void unlock():释放锁
这样就可以实现手动
上锁和手动释放锁
注意:
Lock是接口
不能直接实例化,这里采用它的实现类ReentrantLock
来实例化
ReentrantLock的构造方法:ReentrantLock(),创建一个ReentrantLock的实例
就是在程序中出现了锁的嵌套
又叫做等待唤醒机制
生产者消费者模式是一个十分经典的多线程协作
的模式
我们知道多线程的执行具有随机性
那么,现在我们学习的生产者和消费者模式就要打破这一特性,使得多个线程轮流执行
生产者:生产数据
消费者:消费数据
理想情况
生产者先抢到cpu的执行权,进行生产数据,然后消费者再抢到cpu的执行权,进行消费数据
消费者等待
消费者先抢到cpu的执行权,这时发现没有数据,此时消费者处于等待状态,
当消费者处于等待状态时,生产者会抢到cpu的执行权,判断是否有数据,
如果没有,则生产数据,然后唤醒消费者,消费者进行消费数据
生产者等待
生产者先抢到cpu的执行权,判断是否有数据,有则进行等待
编写多线程代码的套路
阻塞队列方式实现等待唤醒机制
阻塞队列好比是连接生产者和消费者之间的管道
生产者可以把生产的数据放到管道当中
消费者可以在管道中获取数据进而进行消费
我们可以规定
管道中最多可以放多少数据
队列:数据在管道中,好比是排队一样,先进的数据,先出去
阻塞:
放数据时,放不进去,会等着,叫阻塞
取数据时,取不到,也会等着,也叫阻塞
阻塞队列的继承结构
阻塞队列一共实现了4个接口
iterable:表示阻塞队列可利用迭代器进行遍历或者增强for循环
collection:表示阻塞队列是单列集合
Queue:表示队列
BlockingQueue:表示阻塞队列
实现类:
ArrayBlockingQueue:
底层是数组,有界,创建对象时必须指定长度
LinkedBlockingQueue:底层是链表,无界
不是真正的无界,最大为int的最大值
多线程的6种状态
在Java虚拟机当中,关于线程的状态
,真正定义的只有6种
状态,是没有定义运行状态的,
因为,当线程抢到cpu时,那么此时虚拟机就会把当前线程交给操做系统
去管理了,所以就没有定义运行状态