一、多线程基础
1.进程与线程
线程是进程内一个相对独立的、可调度的执行单元,又称为轻量级进程。和进程类似,线程也有运行、就绪、阻塞等状态。线程必须拥有父进程。系统没有为线程分配资源,它与进程中的其他线程共享该进程的共享资源。同一进程的不同线程共享相同的地址空间,它们可以访问相同的变量和对象,实现线程间的信息共享。线程间的通信简单而有效,上下文切换非常快。
进程相当于一个应用程序(以QQ为例),进程间不能通信(因为内存不共享),QQ中的每一个聊天窗口便是线程。
2.多线程的好处
多线程程序是指一个程序中包含多个执行流,它是实现并发机制的有效手段。从逻辑的观点看,多线程意味着一个程序的多个语句快同时执行,但不等于多次启动一个程序
引入多线程设计原因
- 某些应用具有内在的多控制流结构,这些控制流具有合作性质,需要共享内容。采用多线程易于对问题建模
- 在需要多控制流的应用中,多线程比多进程在速度上具有绝对优势。统计表明,线程的建立速度约比进程的建立速度快100倍
- 采用多线程可以提高处理机与设备之间的并行性
- 在多处理机的硬件环境中,多线程可并行执行,从而可提高资源利用率和进程推进速度。
3.run()和start()方法
- run()方法是新线程启动的前提,start()方法是新线程启动的标志
- 当调用start()时,会自动告诉jvm机,此时我们需要开辟新的栈空间
- 当开辟完新的栈空间后,start()方法会自动弹栈,在新栈中,run()方法压栈
- 如果我们直接调用新对象的run()方法,此时不会造成多线程并发,因为此时相当于代码由上至下的顺序执行
- run()方法在分支栈中等价于原栈空间的main
4.多线程的状态
1.新生状态
在创建Thread实例后,此Thread对象就处于新生状态,此时线程已被创建但还未开始执行。是一个空线程对象,还没有分配到系统资源
2.就绪状态(*)
为了得到实际的线程,为线程创建属于它的内存资源,需要使用start()方法启动线程,此时线程属于就绪状态,等待cpu分配执行时间(cpu时间片),自动调用自己的run()方法,开启运行状态
主线程会继续执行start()方法下面的语句,这时run()方法可能还在执行,从而实现了多任务操作
3.运行状态
如果线程不能在一个时间片中执行完毕,会被中断,由执行状态回到就绪状态,等待下一轮cpu分配执行时间
运行状态可以调用yield()方法主动放弃执行,转到就绪状态。仍然可能被再次调用
4.阻塞状态(*)
阻塞状态其实是睡眠、资源阻塞、等待三种状态的结合体,此时线程仍是活的,只是缺乏运行的条件。
引起阻塞状态的因素:
- 睡眠:线程调用sleep()方法睡眠一段时间
- 资源阻塞:线程在等待一种资源
- 等待:调用了wait()方法使线程挂起,直到线程得到notify()或notifyAll()消息
阻塞状态时,会让出cpu,让其他保持就绪状态的线程获得可能的执行时间(cpu时间片)
5.死亡状态
如果线程的run()方法执行完毕,线程正常结束;或者线程执行过程中抛出一个未捕获的异常或错误,线程异常结束。结束后,线程处于死亡状态
一旦线程死亡,就不能复生。如果死亡状态任然调用start()方法,会出现运行时异常IllegalThreadException
二、多线程引例
1.多线程步骤
构建Thread子类对象引发多线程的步骤如下:
- 构建Thread子类,重写其中的run()方法
- 创建线程对象
- 线程对象调用start()方法启动该线程
2.代码实现
public class ThreadDemo {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start(); // 此处如果直接调用myThread.run()方法,会直接进行程序的顺序执行,不 会构成多线程
for (int i = 0; i < 10; i++) {
System.out.println("main-->" + i);
}
}
}
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("myThread-->" + i);
}
}
}
/**
*上面的代码包含三个线程,
1.main线程
2.thread线程
3.GC线程(守护线程)
**/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-amEvnow4-1686493036672)(…/blog示意图/微信图片_20230609180331.png)]
3.代码分析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LOl6zMgH-1686493036673)(…/blog示意图/多线程jvm示意图.png)]
三、多线程应用
多线程最为关键的好处即利用不同的线程操作同一个内容
下面是一个售票的小程序,两个售票员一起售卖100张门票,利用多线程实现
package GoodsTrade.administrator; public class ThreadDemo { public static void main(String[] args) { MyThread myThread = new MyThread(100); myThread.start(); int num = myThread.getNum(); while(num > 0) { myThread.sale(); } } } class MyThread extends Thread { private int num; public MyThread() {} public MyThread(int num) { //构造函数,方便在定义对象时传入售票的票数 this.num = num; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } @Override public void run() { sale(); } public void sale() { while(num > 0) { try { sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(currentThread().getName() + "正在出售第 " + this.num + " 张票,剩余票数:" + --num); setNum(num); } } } //运行结果 /* Thread-0正在出售第 100 张票,剩余票数:99 main正在出售第 100 张票,剩余票数:98 main正在出售第 98 张票,剩余票数:97 Thread-0正在出售第 97 张票,剩余票数:96 Thread-0正在出售第 96 张票,剩余票数:95 main正在出售第 96 张票,剩余票数:94 main正在出售第 94 张票,剩余票数:93 Thread-0正在出售第 93 张票,剩余票数:92 main正在出售第 92 张票,剩余票数:91 Thread-0正在出售第 91 张票,剩余票数:90 main正在出售第 90 张票,剩余票数:89 Thread-0正在出售第 90 张票,剩余票数:88 main正在出售第 88 张票,剩余票数:87 Thread-0正在出售第 88 张票,剩余票数:86 main正在出售第 86 张票,剩余票数:85 Thread-0正在出售第 85 张票,剩余票数:84 Thread-0正在出售第 84 张票,剩余票数:83 main正在出售第 84 张票,剩余票数:83 main正在出售第 83 张票,剩余票数:82 Thread-0正在出售第 82 张票,剩余票数:81 main正在出售第 81 张票,剩余票数:80 Thread-0正在出售第 80 张票,剩余票数:79 Thread-0正在出售第 79 张票,剩余票数:78 main正在出售第 78 张票,剩余票数:77 main正在出售第 77 张票,剩余票数:76 Thread-0正在出售第 77 张票,剩余票数:75 Thread-0正在出售第 75 张票,剩余票数:74 main正在出售第 74 张票,剩余票数:73 Thread-0正在出售第 73 张票,剩余票数:72 main正在出售第 73 张票,剩余票数:72 Thread-0正在出售第 72 张票,剩余票数:70 main正在出售第 72 张票,剩余票数:71 main正在出售第 70 张票,剩余票数:69 Thread-0正在出售第 70 张票,剩余票数:69 Thread-0正在出售第 69 张票,剩余票数:68 main正在出售第 69 张票,剩余票数:68 main正在出售第 68 张票,剩余票数:66 Thread-0正在出售第 68 张票,剩余票数:67 Thread-0正在出售第 66 张票,剩余票数:65 main正在出售第 65 张票,剩余票数:64 main正在出售第 64 张票,剩余票数:63 Thread-0正在出售第 63 张票,剩余票数:62 main正在出售第 62 张票,剩余票数:61 Thread-0正在出售第 62 张票,剩余票数:61 Thread-0正在出售第 61 张票,剩余票数:60 main正在出售第 60 张票,剩余票数:59 Thread-0正在出售第 59 张票,剩余票数:58 main正在出售第 59 张票,剩余票数:57 main正在出售第 57 张票,剩余票数:56 Thread-0正在出售第 57 张票,剩余票数:55 Thread-0正在出售第 55 张票,剩余票数:54 main正在出售第 54 张票,剩余票数:53 Thread-0正在出售第 53 张票,剩余票数:52 main正在出售第 53 张票,剩余票数:52 Thread-0正在出售第 52 张票,剩余票数:51 main正在出售第 51 张票,剩余票数:50 Thread-0正在出售第 50 张票,剩余票数:49 main正在出售第 49 张票,剩余票数:48 Thread-0正在出售第 48 张票,剩余票数:47 main正在出售第 48 张票,剩余票数:47 main正在出售第 47 张票,剩余票数:46 Thread-0正在出售第 46 张票,剩余票数:45 main正在出售第 45 张票,剩余票数:44 Thread-0正在出售第 45 张票,剩余票数:44 main正在出售第 44 张票,剩余票数:43 Thread-0正在出售第 43 张票,剩余票数:42 main正在出售第 42 张票,剩余票数:41 Thread-0正在出售第 41 张票,剩余票数:40 main正在出售第 40 张票,剩余票数:39 Thread-0正在出售第 40 张票,剩余票数:39 Thread-0正在出售第 39 张票,剩余票数:38 main正在出售第 39 张票,剩余票数:38 main正在出售第 38 张票,剩余票数:37 Thread-0正在出售第 37 张票,剩余票数:36 main正在出售第 36 张票,剩余票数:34 Thread-0正在出售第 36 张票,剩余票数:35 main正在出售第 34 张票,剩余票数:33 Thread-0正在出售第 34 张票,剩余票数:33 Thread-0正在出售第 33 张票,剩余票数:32 main正在出售第 32 张票,剩余票数:31 Thread-0正在出售第 31 张票,剩余票数:30 main正在出售第 31 张票,剩余票数:30 main正在出售第 30 张票,剩余票数:29 Thread-0正在出售第 29 张票,剩余票数:28 Thread-0正在出售第 28 张票,剩余票数:27 main正在出售第 27 张票,剩余票数:26 main正在出售第 26 张票,剩余票数:25 Thread-0正在出售第 26 张票,剩余票数:24 Thread-0正在出售第 24 张票,剩余票数:23 main正在出售第 23 张票,剩余票数:22 Thread-0正在出售第 22 张票,剩余票数:21 main正在出售第 22 张票,剩余票数:20 Thread-0正在出售第 19 张票,剩余票数:18 main正在出售第 20 张票,剩余票数:19 main正在出售第 18 张票,剩余票数:17 Thread-0正在出售第 18 张票,剩余票数:17 main正在出售第 17 张票,剩余票数:16 Thread-0正在出售第 17 张票,剩余票数:16 Thread-0正在出售第 16 张票,剩余票数:15 main正在出售第 15 张票,剩余票数:14 Thread-0正在出售第 14 张票,剩余票数:13 main正在出售第 14 张票,剩余票数:13 main正在出售第 13 张票,剩余票数:12 Thread-0正在出售第 13 张票,剩余票数:11 main正在出售第 11 张票,剩余票数:10 Thread-0正在出售第 11 张票,剩余票数:9 main正在出售第 9 张票,剩余票数:8 Thread-0正在出售第 9 张票,剩余票数:8 main正在出售第 8 张票,剩余票数:7 Thread-0正在出售第 7 张票,剩余票数:6 main正在出售第 6 张票,剩余票数:5 Thread-0正在出售第 6 张票,剩余票数:4 main正在出售第 4 张票,剩余票数:3 Thread-0正在出售第 4 张票,剩余票数:2 Thread-0正在出售第 2 张票,剩余票数:1 main正在出售第 2 张票,剩余票数:0 */