JAVAEE初阶相关内容第二弹--多线程(初阶)

目录

认识线程(Thread)

相关概念

线程的概念

为什么要有线程

※进程与线程的区别

Java线程和操作系统线程的关系

创建线程

法一:继承Thread类,重写run()

执行的顺序?

start() 与run()

系统查看进程

重载与重写

new N_Thread

法二:实现Runnable接口(解耦合)

抽象类和普通类的区别:

法三:使用匿名内部类创建Thread的子类

法四:使用匿名内部类实现Runnable

法五:使用Lambda表达式(简单+推荐)


认识线程(Thread)

相关概念

线程的概念

一个线程就是一个“执行流”,每个线程之间都可以按照顺序执行自己的代码,多个线程之间执行多份代码。

线程被称为“轻量级进程”。一个进程可以包含一个或多个线程(且不能没有),同一个进程里的多个线程之间共用进程的同一份资源(这里的资源包括内存、文件描述符表等)。

操作系统在进行实际的调度时,是以线程为单位进行的,如果每个进程有多个线程,每个线程都是独立在CPU上调度的。线程是操作系统调度执行的基本单位。

为什么要有线程

第一“并发编程”称为“刚需”

进入了CPU的多核心时代,CPU再继续做小就变得更加困难,要想进一步的提高程序执行速度,就需要充分利用CPU的多核资源。

有些任务场景需要“等待IO”,为了让等待IO的时间能够去做一些其他的工作,也需要用到并发编程。

第二虽然多进程也可以 实现并发编程,但是线程比进程更轻量。

进程太“重”,创建、开发、销毁进程的开销都是比较大的,说进程重,主要是重在了“资源分配/回收”上。 所以引入了线程,解决并发编程的前提下让创建、销毁、调度的速度更快。

第三线程虽然比进程轻量,但是人们还是不满足,于是又有了”线程池“(ThreadPool)和”协程“(Coroutine)

暂不记录,后续博客中会有相关内容梳理。

※进程与线程的区别

(1)进程是包含线程的,每个进程至少有一个线程的存在,即主线程。

(2)进程和进程之间不共享内存空间,同一个进程的线程之间共享了进程的同一份资源(主要指的是内存和文件描述符表)。

(3)进程是系统分配资源的最小单位,线程是系统调度的最小单位。

一个线程也是通过一个PCB来描述的,一个进程可能对应一个PCB,也可能对应多个。在前一篇博客中所介绍的PCB里的状态,上下文、优先级、记账信息都是每个线程有自己的,但是在同一个进程里的PCB之间,pid是一样的,内存指针和文件描述符表也是相同的。

Java线程和操作系统线程的关系

线程是操作系统中的概念,操作系统内核实现了线程这样的机制,并且对用户提供了一些API供用户使用。Java标准库中的Thread类可以视为是对操作系统提供的API进行了进一步的抽象和封装。

创建线程

创建线程的五种方式

(1)继承Thread类,重写run()

(2)实现Runnable接口

(3)使用匿名内部类,继承Thread

(4)使用匿名内部类,实现Runnable

(5)使用lambda表达式

法一:继承Thread类,重写run()

代码展示:

class N_Thread extends Thread{
    @Override
    public void run() {
        System.out.println("hello");
    }
}
public class ThreadD1 {
    public static void main(String[] args) {
        Thread thread =new N_Thread();
        thread.start();
    }
}

运行结果:

我们在创建的N_ Thread线程上和主线程上同时进行输出,来体会一下同时运行的两个线程,为了更直观的感受,会在两个循环里加入sleep()函数,让结果呈现的速度变慢。

代码展示:

class N_Thread extends Thread{
    @Override
    public void run() {
        while(true){
            System.out.println("helloNThread");
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class ThreadD1 {
    public static void main(String[] args) {
        Thread thread =new N_Thread();
        thread.start();
        while(true){
            System.out.println("主线程");
            try {
                Thread.sleep(1000);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}

运行结果:

法一中需要注意的一些问题:

执行的顺序?

抢占式执行,虽然是存在优先级的,但是在应用程序层面上无法进行修改,内核本身并非是随机的,但是因为干预的因素太多,无法感知细节,所以就只能认为是随机的。

start() 与run()

start: 是真正的独立创建了一个线程(从系统这里创建的),线程是独立的执行流。

run:只是描述了线程要做的工作,如果直接在主函数中调用run方法,此时是没创建新的线程,全是主线程自己做。

系统查看进程

通过jdk中自带的工具jconsole可以查看当前java中的所有的进程

重载与重写

重载:Overload.同一作用域,多个方法,名字相同,参数的个数或类型不同,是同一个类里或者是子类和父类之间。

重写:Override 父亲有个方法子类也搞了一个名字相同,参数也完全相同,子类的方法就会被动态绑定的机制,会被调用。

new N_Thread

对象操作不能创建线程(说的线程指的是系统内核中的PCB)

调用start才是创建PCB,才有货真价实的线程。

调用的start会生成一个新线程,新线程去执行run。

法二:实现Runnable接口(解耦合)

Runnable的作用,描述一个”要执行的任务“,run方法就是任务的执行细节。

代码展示:

class MyRunnable2 implements Runnable{

    @Override
    public void run() {
        System.out.println("hello2");
    }
}
public class ThreadD2 {
    public static void main(String[] args) {
        Runnable runnable = new MyRunnable2();
        Thread t = new Thread(runnable);
        t.start();
    }

}

运行结果:

法二中需要注意的问题:

抽象类和普通类的区别:

抽象类不能实例化,不能直接new,必须搞个子类来继承抽象类。抽象类里还有抽象方法,抽象方法没有方法体,需要让子类重写。

法三:使用匿名内部类创建Thread的子类

代码展示:

public class ThreadD3 {
    public static void main(String[] args) {
        Thread  t =new Thread(){
            @Override
            public void run() {
                System.out.println("使用匿名内部类创建Thread的子类");
            }
        };
        t.start();
    }
}

运行结果:

法三中需要注意的问题:

(1) 创建了一个Thread类的子类,子类没有名字所以叫做”匿名“;

(2)创建了子类的实例,并且让t引用指向该实例。

法四:使用匿名内部类实现Runnable

代码展示:

public class ThreadD4 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("使用匿名内部类实现Runnable");
            }
        });
        thread.start();
    }
}

输出结果:

 本质上和方法2实现Runnable接口相同,只不过把实现Runnable任务交给匿名内部类语法,此处是创建了一个类,实现Runnable,同时创建了类的实例,并且传给了Thread的构造方法。

法五:使用Lambda表达式(简单+推荐)

lambda:匿名函数,用一次即可销毁。

java里面函数没法脱离类存在,java为了和其他语言对齐,弄了个函数式接口,通过这个接口来实现lambda。

代码实现:

public class ThreadD5 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            System.out.println("使用Lambda表达式创建线程");
        }
        );
        t.start();
    }
}

输出结果:

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

西西¥

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

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

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

打赏作者

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

抵扣说明:

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

余额充值