多线程(1)——Thread 类

1. 线程(Thread)

1.1 概念

1.1.1 线程是什么

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

1.1.2 为什么要有线程

首先,“并发编程”成为“刚需”

  • 单核 cpu 的发展遇到了瓶颈,要想提高算力,就需要多核 cpu,而并发编程能更充分利用多核 cpu 资源
  • 有些任务场景需要“等待 IO”,为了让等待 IO 的时间能够去做一些其他工作,也需要用到并发编程

其次,虽然多进程也能实现并发编程,但是线程比进程更轻量

  • 创建线程比创建进程更快(因为创建线程省去了“分配资源”的过程,一旦创建进程,同时也会创建第一个线程,此时就会分配资源,一旦后续创建更多线程,就不必重新再分配资源了)
  • 销毁线程比销毁进程更快(因为销毁线程省去了“释放资源”的过程)
  • 调度线程比调度进程更快 

最后,人们不满足于线程的轻量,又有了“线程池(ThreadPool)”和 “协程(Coroutine)”

1.1.3 进程和线程的区别

  • 进程包含线程,每个进程至少有一个线程存在,即主线程
  • 进程是系统“资源分配”的基本单位,线程是系统“调度执行”的基本单位
  • 进程和进程之间不共享内存空间,同一个进程的线程之间共享同一份系统资源(包括内存、硬盘、网络宽带等;在编程中,多个线程是可以公用同一份变量的)
  • 线程是当下实现并发编程的主流方式,通过多线程就可以充分利用好多核 cpu,但并不是线程数目越多越好,线程数目达到一定程度,把多个核心充分利用后,此时若继续增加线程,无法再提高效率,甚至可能会影响效率
  • 多个线程之间,可能会相互影响(线程安全问题),一个线程抛出异常,可能会把其他线程一起带走
  • 多个进程之间,一般不会相互影响,一个进程崩溃了,不会影响到其他进程,这一点称为“进程的隔离性”

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

线程是操作系统中的概念,操作系统内核实现了线程这样的机制,并且对用户层提供了一些 API 供用户使用(如 Linux 中的 pthread 库)

Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进行了进一步的抽象和封装

1.2 创建线程

方法1:继承 Thread 类

继承 Thread 来创建一个线程类

//此处 Thread 类可以直接使用,不需要导入任何包,因为其包含于 java.lang
class MyThread extends Thread {
    //继承 Thread 的主要目的就是为了重写 run 方法
    @Override
    public void run() {
        //这里写的代码,就是即将创建出的线程要执行的逻辑
        System.out.println("hello Thread");
    }
}
public class Demo1 {
    public static void main(String[] args) {
        //创建 MyThread 类的实例
        MyThread t = new MyThread();

        //调用 start 方法
        //会在进程内部创建出一个新的线程
        //新的线程就会执行 run 里面的代码
        t.start();
    }
}

执行结果:


tip:上面 run 方法,用户手动定义了,但没有手动调用,最终这个方法被 系统/库/框架 进行调用了,此时这样的方法就称为“回调函数”(callback)

例如:

  • C 中的函数指针主要有两个用途:1. 作为回调函数;2. 实现转移表,降低代码的复杂程度
  • Java 数据结构中的优先级队列(堆),必须先定义好对象的“比较规则”;如:Comparable 中的 compareTo 和 Comparator 中的 conpare,都是自己定义,但没有调用,此时都是由标准库本身内部的逻辑负责调用的

上面代码运行起来是一个进程,但是这个进程中包含了两个线程

调用 main 方法的线程称为“主线程”;t.start(); 又手动创建了新的线程

主线程和新线程就会 并发/并行 的在 cpu 上执行


由于程序只执行一次,速度很快,看不出线程相关,所以给程序加上 while 循环:

class MyThread extends Thread {
    //继承 Thread 的主要目的就是为了重写 run 方法
    @Override
    public void run() {
        //这里写的代码,就是即将创建出的线程要执行的逻辑
        while(true) {
            System.out.println("hello Thread");
            //循环中加上休眠操作,让循环每循环一次都休息一会,避免 cpu 消耗过大
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class Demo1 {
    public static void main(String[] args) throws InterruptedException {
        //创建 MyThread 类的实例
        MyThread t = new MyThread();

        //调用 start 方法创建线程
        t.start();

        while(true) {
            System.out.println("hello main!");
            Thread.sleep(1000);
        }
    }
}

我们查看运行结果可发现:多个线程之间,谁先去 cpu 上调度执行,这个过程是“不确定的”(此处不是数学意义的随机)

这个调度顺序,取决于操作系统内核里“调度器”的实现

调度器里有一套规则,但是我们作为应用程序开发,没法进行干预,也感受不到,只能把这个过程近似的视为“随机”(抢占式执行),并不属于伪随

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值