多线程
进程与线程的关系
进程是一个应用程序(1个进程是一个软件)
线程是一个进程中的执行场景/执行单元
一个进程可以启动多个线程
对于java程序来说,会先启动jvm(一个进程),jvm再启动一个主线程调用main方法。同时再启动一个垃圾回收线程负责看护,回收垃圾。所以一个java程序至少有两个线程并发。
注意:
- 进程A和进程B的内存独立不共享(因为分属于不同的软件)
- 在java语言中线程A与线程B,堆内存和方法区内存共享;但是栈内存对立,一个线程一个栈
- 在使用了多线程机制后,main方法结束只是主线程结束了,主栈空了,其他的栈(线程)可能还在压栈弹栈
假设启动10个线程,会有10个栈空间,每个栈和每个栈之间,互不干扰,各自执行各自的,这就是多线程并发。
java中之所以有多线程机制,目的就是为了提高程序的处理效率。

解疑
分析一个问题:对于单核的CPU来说,真的可以做到真正的多线程并发吗?
对于多核CPU电脑来说,是可以真正的做到多线程并发的。
对应单核CPU来说,仅有一个处理器,不能够真正的多线程并发,但是可以给人一种“多线程并发”的感觉。由于CPU的处理速度极快,多线程之间频繁切换执行。
多线程实现方法一
编写一个类,直接继承java.lang.Thread, 重写run方法。
class MyThread extends Thread{
@Override
public void run(){
for (int i = 0; i < 1000; i++) {
System.out.println("分支线程----------->"+i);
}
}
run和start的区别
在主线程中直接调用run()方法
public class ThreadTest {
public static void main(String[] args) {
//这里是main方法,这里的代码属于主线程,在主线程中运行
//新建一个分支线程对象
MyThread t = new MyThread();
t.run(); //不会启动线程,不会分配新的分支栈。(这种方法就是单线程)
//这里的代码还是运行在主线程中
for (int i = 0; i <1000 ; i++) {
System.out.println("主线程---------->"+i);
}
}
}
}
运行内存图

在主线程中调用start()方法
public class ThreadTest {
public static void main(String[] args) {
//这里是main方法,这里的代码属于主线程,在主线程中运行
//新建一个分支线程对象
MyThread t = new MyThread();
//启动线程
//start()方法的作用是:启动一个分支线程,在JVM中开辟一个新的栈空间,这段代码任务完成后,瞬间就结束了。
//这段代码的任务只是为了开启一个新的栈空间,只要新的栈空间开出来了,start()方法就结束了。线程就启动成功了。
//启动成功的线程会自动调用run方法,并且run方法在分支栈的栈底部(压栈)
//run方法在分支栈的栈底部,main方法在主栈的栈底部。run和main是平级的。
t.start();
//这里的代码还是运行在主线程中
for (int i = 0; i <1000 ; i++) {
System.out.println("主线程---------->"+i);
}
}
}
}

多线程实现方法二
编写一个类,实现java.lang.Runnable 接口, 实现run方法。
第二种方式实现接口比较常用,因为一个类实现了结构,它还可以去继承其他的类,更灵活。
class MyRunnable implements Runnable{
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("分支线程----------->"+i);
}
}
}
普通实现方式
public class ThreadTest02 {
public static void main(String[] args) {
//创建一个可运行的对象
MyRunnable runnable = new MyRunnable();
//将可运行的对象封装成一个线程对象
Thread t = new Thread(runnable);
// Thread t = new Thread(new MyRunnable());
//启动线程
t.start();
//这里的代码还是运行在主线程中
for (int i = 0; i <10 ; i++) {
System.out.println("主线程---------->"+i);
}
}
}
采用匿名类方式
public class ThreadTets03 {
public static void main(String[] args) {
//创建线程对象,采用匿名类的方式
Thread t = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("分支线程----------->"+i);
}
}
});
t.start();
//这里的代码还是运行在主线程中
for (int i = 0; i <100 ; i++) {
System.out.println("主线程---------->"+i);
}
}
}
线程的生命周期
程序的输出结果特点为:有先有后,有多有少。

线程的生命周期一共有5个状态:新建转状态,就绪状态,运行状态,死亡状态,阻塞状态。如图所示

就绪状态
就绪状态的线程又叫做可运行状态,表示当前线程具有抢夺CPU时间片的权限(CPU时间片就是执行权)。当一个线程抢夺到CPU时间片之后,就开始执行run方法,run方法的开始执行标志着线程进入运行状态
运行状态
run方法的开始执行标志着这个线程进入运行状态,当之前占有的CPU时间片用完后,当再次抢到CPU时间后,会重新进入run方法接着上一次的代码继续执行。
阻塞状态
当一个线程遇到阻塞事件,例如接收用户键盘输入,或者sleep方法等。此时线程会进入阻塞状态,阻塞状态的线程会放弃之前占有的CPU时间片。等阻塞状态结束后,需要再次回到就绪状态,重新抢夺CPU时间片
本文深入探讨Java多线程机制,解析进程与线程的关系,详细阐述Java中线程的实现方法,包括继承Thread类和实现Runnable接口两种方式。同时,文章还介绍了线程的生命周期,帮助读者理解线程从新建到死亡的全过程。
132

被折叠的 条评论
为什么被折叠?



