本文已参与「新人创作礼」活动,一起开启掘金创作之路。
多线程
多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。简单地说,就是一个同一个跑道上在跑步的人,这些人就可以当作是线程,而跑道则可以当作是时间段。生活中,我们用的手机、电脑能够同时进行聊天、看视频、听音乐等,就是多线程的功劳。
1. 线程和进程
所谓进程,即一个内存中运行的应用程序。每个进程都有自己独立的内存空间,一个进程可以有多个线程(1,n)。
所谓线程,即进程中的一个执行任务(控制单元)。每个进程可以运行多个线程,多个线程可以共享信息。
2. 并发和并行
并发,即同一时间段执行多个任务。
并行,即同一时间点执行多个任务。
3. 线程的创建和启动
3.1 继承 Thread 类
-
自定义类继承Thread类
-
重写run()方法
-
创建自定义类对象
-
调用start()方法
3.2 实现Runnable接口
- 自定义类实现Runnable接口
- 实现run()方法
- 创建自定义类对象
- 创建Thread对象并将自定义类对象作为对象传入
- 调用start()方法
3.3 两种方式比较
(1)从类和接口的特性上分析
- Java中类只能单继承,继承Thread类后将不能继承其它直接父类
- Java中类可以多实现接口,实现Runnable接口后可以继承其它类,也可以实现其它接口
(2)从操作上分析
- 继承方式和获取线程名字都比较简单
super.getName() - 实现方式和获取线程名字都比较麻烦
Thread.currentThread().getName()
(3)从多线程共享同一资源上分析
- 继承方式多个线程不能共享同一个资源
- 实现方式多个线程能够共享同一个资源
4. 线程执行的随机性
一个线程启动之后将成为一个独立的个体,等待CPU的调度分配资源,不会因为启动它的外部线程结束而结束。
5. 线程的生命周期
| 状态名称 | 说明 |
|---|---|
| 初始状态(NEW) | 表示线程被创建了,但没有调用start()方法,由Java虚拟机为其分配内存并初始化成员变量值 |
| 运行状态(RUNNABLE) | 可以细分为就绪状态(READY)和运行状态(RUNNING)两种状态。 就绪状态:当线程调用start()方法后,线程就处于就绪状态,进入了线程队列排队,但此时线程并未开始执行,仅仅是获得了运行的资格,而运行的时期取决于CPU调度器的调度。 运行状态:表示线程对象被CPU调度器调度了,可以执行线程体。 |
| 阻塞状态(BLOCKED) | 表示正在运行的线程遇到某种特殊情况,比如同步、等待I/O操作完成等。进入阻塞状态的线程让出CPU资源,并暂停自己的执行。 |
| 等待状态(WAITING) | 进入该状态表示当前线程需要等待其它线程做出一些特定动作(比如调用notify、notifyAll方法),才能够重新进入RUNNABLE状态 |
| 超时等待状态(TIME_WAITING) | 与等待状态不同,处于该状态的线程达到设定的时间后可以自行返回 |
| 终止状态(TERMINATED) | 表示当前线程已经执行完毕 |
6. 常用方法
| 方法 | 说明 |
|---|---|
| join() | 使线程进入阻塞状态,只有线程执行完才往下执行 |
| sleep(long millis) | 使正在执行的线程进行暂停一段时间(单位:毫秒),进入阻塞状态(常用于模拟网络延迟) |
| getPriority() | 获取线程的优先级(1~10),默认为5(优先级高低只与线程获得执行机会的次数多少有关) |
| setPriority(int n) | 更改线程的优先级 |
| setDaemon(boolean on) | 将线程标记为守护线程或用户线程(必须在start()调⽤前,否则抛IllegalThreadStateException异常) |
7. 线程同步
7.1 解决方法
(1)同步代码块
synchronized(同步锁){
}
(2)同步方法
- 使用synchronized修饰的方法(将需要同步的代码抽取为一个方法,并使用synchronized修饰)
- 同步锁是谁?
- 对于非静态方法,同步锁为this
- 对于静态方法,同步锁为类名.class
(3)同步锁
- 同步锁又称为同步监听对象/同步监听器/互斥锁\
- Java程序允许使用任何对象作为同步监听对象,一般选择当前并发访问的共同资源作为同步监听对象(this、类名.class)
- 在任何时候,最多允许一个线程拥有同步锁,获得同步锁的线程先执行,其它线程在代码块外等候