Java- 线程

本文深入探讨Java多线程机制,解析进程与线程的关系,详细阐述Java中线程的实现方法,包括继承Thread类和实现Runnable接口两种方式。同时,文章还介绍了线程的生命周期,帮助读者理解线程从新建到死亡的全过程。

多线程

进程与线程的关系

进程是一个应用程序(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);
        }
    }
}
}

运行内存图
222

在主线程中调用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);
        }
    }
}
}

2222

多线程实现方法二

编写一个类,实现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);

        }
    }
}

线程的生命周期

程序的输出结果特点为:有先有后,有多有少。
wwww
线程的生命周期一共有5个状态:新建转状态,就绪状态,运行状态,死亡状态,阻塞状态。如图所示
2222wwwwww

就绪状态

就绪状态的线程又叫做可运行状态,表示当前线程具有抢夺CPU时间片的权限(CPU时间片就是执行权)。当一个线程抢夺到CPU时间片之后,就开始执行run方法,run方法的开始执行标志着线程进入运行状态

运行状态

run方法的开始执行标志着这个线程进入运行状态,当之前占有的CPU时间片用完后,当再次抢到CPU时间后,会重新进入run方法接着上一次的代码继续执行。

阻塞状态

当一个线程遇到阻塞事件,例如接收用户键盘输入,或者sleep方法等。此时线程会进入阻塞状态,阻塞状态的线程会放弃之前占有的CPU时间片。等阻塞状态结束后,需要再次回到就绪状态,重新抢夺CPU时间片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

piepis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值