【韩顺平】Java线程(基础)知识点总结

文章目录

1.线程概念

1.1程序

1.2进程

1.3线程

2.其他相关概念

2.1并发

2.2并行

2.3单线程

2.4多线程

3.创建线程的两种方法

3.1继承Thread类,重写run方法

3.1.1多线程的机制

3.1.2为什么启动线程用的是cat.start();而不是直接用cat.run();

  3.2实现Runnable接口,重写run方法


        此篇文章总结自韩顺平老师所讲解的Java线程内容,我将会在引用韩老师原文的基础上增加自己的一些解读,以加深各位小伙伴对于Java线程的理解。希望能为各位学习Java的小伙伴带来帮助。下面让我们先来了解一下线程的一些概念。

1.线程概念

1.1程序

是为了完成特定任务,用某种语言编写的一组指令的集合

简单来说:就是我们所编写的代码

1.2进程

1.进程是一个独立的运行单位,也是操作系统进行资源分配和调度的基本单位。它由进程控制块(核心),程序段和数据段三部分组成

2.进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存空间,当我们使用微信,就又启动了一个进程,操作系统将为微信分配新的内存空间

3.进程是程序的一次执行过程,或是正在运行的一个程序,是动态过程:有他自身的产生,存在和消亡的过程

1.3线程

1.线程由进程创建的,是进程的一个实体

2.一个进程可以拥有多个线程

2.其他相关概念

2.1并发

同一时刻,多个任务交替执行,造成一种“貌似同时”的错觉,简单地说,单核CPU实现的多任务就是并发

2.2并行

同一时刻,多个任务同时执行,多核CPU可以实现并行

2.3单线程

同一时刻,只允许执行一个线程

2.4多线程

同一时刻,可以执行多个线程

概念了解完毕后,下面介绍现线程的使用方法

3.创建线程的两种方法

3.1继承Thread类,重写run方法

下面通过一个案例演示此种创建方法

提出需求:

1.编写程序,开启一个线程,该线程每隔1秒,在控制台输出"猫咪学习java中"

2.当输出80次"猫咪学习java中"时结束该进程

代码如下:

public class Thread01 {
    public static void main(String[] args) throws InterruptedException {
        //创建Cat对象,可以当作线程使用
        Cat cat = new Cat();
        cat.start();//启动线程->最终执行cat的run方法
        //说明:当main线程启动一个子线程Thread-0,主线程不会阻塞,会继续执行后面代码
        System.out.println("主线程继续执行 "+Thread.currentThread().getName());
        for (int i = 0; i < 5; i++) {
            System.out.println("主线程 i="+i);
            //让主线程休眠1秒
            Thread.sleep(1000);
        }
    }
}

class Cat extends Thread{//当一个类继承了Thread类,该类就可以当作线程使用
    @Override
    public void run() {//重写run方法,实现自己的业务逻辑
        int times=0;
        while(true){
            //该线程每隔1秒,在控制台输出"猫咪学习java中"
            System.out.println("猫咪学习Java中"+"线程名"+(++times)+Thread.currentThread().getName());
            try {
                //使该线程休眠1秒
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (times==8){
                break;//当times到8次时,线程退出
            }
        }
    }
}

为帮助大家更好的了解这段代码中线程创建的流程,下面讲解多线程的机制

3.1.1多线程的机制

以该代码为例

        当我们运行程序时,就相当于启动了一个进程,然后,程序马上会进入我们的main方法中,进入main方法后,这时进程就开启了一个主线程叫做main线程。在这个主线程中,我们创建了一个Cat对象,由于这个Cat对象继承了Thread类,所以我们可以将其当作线程使用,因此当我们调用cat.start();时,我们的主线程就也创建了一个子线程叫做Thread-0线程,并且不会导致主线程阻塞(即主线程不会等到cat.start();方法执行完毕后,才继续执行后面代码

        如果我们运行程序,就会看到主线程和Thread-0线程交替执行,直到某一个线程先消亡,系统才会只执行那个未消亡的线程(但此时应用程序(进程)并未结束,只有所有线程都消亡了,我们的应用程序(进程)才会结束

3.1.2为什么启动线程用的是cat.start();而不是直接用cat.run();

        因为run方法只是一个普通方法,他并没有开启一个新的线程,因此如果我们在主线程中直接调用run方法,则自始至终都只有主线程在运行,导致主线程会发生阻塞(即系统会执行完run方法中的所有内容后再开始执行主线程中的后续代码)

        下面通过源码解读cat.start()方法是如何启动线程的:

1.当我们调用cat.start();时,系统会进入public synchronized void start() {} 这个方法

public synchronized void start() {
        group.add(this);
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

 2.接着public synchronized void start() {} 这个方法会调用其中的核心方法start0();

start0()是一个本地方法,由JVM调用,底层由c/c++实现

真正实现多线程效果的是start0()方法,而不是run()方法

3.最后再在start0()方法中调用run()方法

private native void start0();
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

  3.2实现Runnable接口,重写run方法

        由于Java是单继承的,在某些情况下一个类可能已经继承了某个父类,这时在用继承Thread类来创建线程是不可能的了,因此Java设计者们提供了实现Runnable接口的方法来创建线程

下面继续通过一个案例演示这种线程创建方法

提出需求:

请编写程序,该程序可以每隔1秒,在控制台输出"hi",当输出10次后,自动退出

代码如下:

public class Thread02 {
    public static void main(String[] args) {
        Dog dog=new Dog();
        //dog.start();这里不能使用start
        //创建Thread对象,把dog对象(实现Runnable接口),放入Thread
        Thread thread=new Thread(dog);
        thread.start();
    }
}
class Dog implements Runnable{//通过实现Runnable接口,开启线程
    int count=0;

    @Override
    public void run() {
        while (true){
            System.out.println("hi"+(++count)+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(count==10){
                break;
            }
        }
    }
}

注意:

1.用实现Runnable接口的方法来创建线程时,创建对象后,不能用对象名.start()的方式开启线程,因为Runnable接口中没有start()方法而只有一个run()方法可以调用,虽然如此,我们仍然不能直接用对象名.run()的方式来开启线程,原因在3.1.2中已经分析过

2.解决办法:创建Thread对象,把我们需要当作线程的对象(实现Runnable接口)放入Thread中

然后再通过调用Thread对象中的start()方法完成线程的创建

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小小西瓜呀

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

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

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

打赏作者

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

抵扣说明:

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

余额充值