操作系统_多线程知识笔记(一)

前言:

为什么要引入多线程编程

java引用进程的概念主要为了解决 “并发编程” 的问题,即多个程序一起运行;
锁紧弄成编程已经可以解决并发编程的问题,并且可以利用CPU多核资源了
在这里插入图片描述

因此,线程也就应运而生,线程也叫 “轻量级进程”;
解决并发编程问题,最终是为了让创建,销毁,调度的速度更快;

1.如何理解线程

为什么线程更轻?
因为线程把创建资源,释放资源的过程都给省下了

如何理解线程
看例子:
上篇博客我们把纺织厂的例子来比喻进程,这篇博客继续使用这个例子:
在这里插入图片描述
为什么说线程把创建资源,释放资源的过程都给省下了呢?
因为 线程A和线程B共享进程里面的资源,就相当于本来是1个人吃10只鸡,多加了一个线程之后就相当于多加了一个人,现在就相当于2个人吃10只鸡;一个进程里面的所有线程都是资源都是共享的,因此创建线程不需要创建和释放资源

2.进程和线程的关系

  1. 进程和线程的关系是进程包含线程,一个进程最少有一个线程,也可以有多个线程;但是进程里面的线程应该视具体资源而定,不能一味增加,否则会造成程序崩溃
  2. 同一个进程里多个线程之间,共用了进程的同一份资源(内存文件描述符表)
    注意:在同一个进程中,线程1 new的对象,线程2,3都可以直接使用,
    线程1 打开的文件在线程2,3里都可以直接使用
  3. 操作系统实际调度时,是以线程为基本单位调度的,上篇文章说操作系统是以进程为基本单位调度,是一个进程里面只有一个线程的前提下;如果每个进程都有多个线程,每个线程都是独立在CPU上调度的,每个线程也都有自己的执行逻辑 (执行流);
  4. 一个核心执行的是一个线程,如果一个进程有两个线程,那么线程A可能在 核心1上执行,线程B可能在核心2上执行,实际调度过程中,不关心进程,只关心线程;
  5. 一个线程也是通过PCB来描述的,一个进程里面可能对应一个PCB,也可能对应多个PCB,上篇博客里介绍的PCB状态,上下文,优先级,记账信息等都是每个线程所特有的,但是一个进程里的pid,内存指针和文件描述符表都是相同的

画图解释一下多进程和多线程的关系
在这里插入图片描述
第一种方式是多进程,会浪费调大量资源,花费大量成本,去重新申请一个进程
第二种是多线程方式,直接在一个进程里完成即可,省下很多成本,并且提高了速度

重点:是不是一味的在一个进程里面申请线程,速度就可以一直提升呢?
答案肯定是不行的,增加线程数量的时候,也不是一直可以提高速度的,因为纺织厂的空间是有限的,生产线过多,机会拥挤,反而会影响速度;同理,线程太多,核心数目有限,大量的时间反而浪费在线程调度上了

3.多线程编程

java中操作多线程,最核心的类是Thread,记住就行了;不要纠结为啥是这个类
创建线程的目的是为了成立一个独立的执行流(执行一段代码)

第一种:继承Thread类

看代码:

class MyThread extends Thread{
    //重写子类的 run()方法,告诉线程要做什么工作
    @Override
    public void run() {
        while(true){
            System.out.println("==MyThread==");
            //休眠1s,让线程运行速度变慢,方便观看效果
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}


public class Test1 {

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new MyThread();
        thread.start();//真正创建了一个线程
        
        //理解为死循环打印==main==即可
        while(true){
            System.out.println("==main==");
            thread.sleep(1000);//休眠1s,让线程运行速度变慢,方便观看效果
        }
    }
}

在这里插入图片描述
问题:为什么不在main()中调用run方法?
如果在main()调用run,此时就没有创建新线程,全程都只有main线程在运行

在这里插入图片描述
在这里插入图片描述
以上就是多线程编程的一个典型例子,即main线程和thread线程同时执行,谁先谁后我们也不确定;


  1. 操作系统调度线程的时候,是==“抢占式执行”==,具体哪个线程在先,哪个线程在后,取决于操作系统调度器,实现具体策略
  2. new Thread对象,并不是创建线程(这里说的线程是 系统内核里的 PCB),调用start才是创建PCB才是货真价实的线程
  3. PCB对应的是线程,一个进程最少有一个PCB,也可以有多个PCB,同一个进程的pid是相同的,不同进程的pid是不同的
  4. PCB是一个数据结构,体现的是进程/线程是如何实现,如何被描述出来的

java中创建线程的写法有很多种,上面写的是第一种即继承Thread,重写run方法

第二种:实现Runnable 接口:

class MyRunnable implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("==MyRunnable==");
            try {
                sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    }
}

public class Test1 {

    public static void main(String[] args) throws InterruptedException {

        Runnable runnable = new MyRunnable();//创建一个任务
        Thread thread = new Thread(runnable);//把任务交给线程来处理
        thread.start();//真正创建了一个线程,去执行任务
        
       //理解为死循环打印==main==即可
        while(true){
            System.out.println("==main==");
            sleep(1000);//休眠1s,让线程运行速度变慢,方便观看效果
        }

    }
}

结果:打印如果依旧是 顺序不确定的
在这里插入图片描述

为什么要这样写? 目的是为了让线程和线程之间要做的工作分开.解耦合;

第三种:使用Lambda表达式

这一种方法是最推荐的,也是最方便的

public static void main(String[] args) {
//直接把Lambda任务传给Thread构造方法
        Thread thread = new Thread(() ->{
            System.out.println("==Lambda==");
        });
        thread.start();
        System.out.println("==main==");
    }

4.Thread 用法

1.Thread常见的构造方法

在这里插入图片描述

    //构造方法举例
		Thread t1 = new Thread();
        Thread t2 = new Thread(new MyRunnable());
        Thread t3 = new Thread("名字");
        Thread t4 = new Thread(new MyRunnable(), "名字");

2.Thread的几个常见的属性

在这里插入图片描述

  1. 获取id和名字
 public static void main(String[] args) {
        Thread thread1 = new Thread("第一个线程的名字");
        System.out.println(thread1.getName());//获取线程的名字
        System.out.println(thread1.getId());//获取线程的id
    }

结果:
在这里插入图片描述


2.获取线程状态
getState()方法;

public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            System.out.println("==thread1==");
        });
        thread1.setDaemon(true);
        thread1.start();//线程运行
        System.out.println(thread1.getState());//在线程正在运行是获取线程状态,就是runnable
        thread1.join();//等到线程结束
        System.out.println(thread1.getState());//线程结束之后,再获取线程状态就是结束的状态了,TERMINATED
    }

运行结果:
在这里插入图片描述


  1. 看看线程状态是否存活
    isAlive()方法:是判断当前系统里面的 线程 是不是真的存在,并不是判断对象是否真的存在
    在这里插入图片描述

在这里插入图片描述

 public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            System.out.println("==thread1==");
        });
      
        System.out.println(thread1.isAlive());//false,并没有创建线程,只是创建了对象,所以是false
        thread1.start();
        System.out.println(thread1.isAlive());//true,创建了线程,并且并没有执行完,所以是true
      
        thread1.join();
       
        System.out.println(thread1.isAlive());//false,线程已经执行完任务并且线程已经销毁,所以线程状态是false

    }
如果thread的run还没跑,isAlive()就是false; 如果thread的run正在跑,isAlive()就是true; 如果thread的run跑完了,isAlive()就是false;
  1. 线程中断
    这里的线程中断不是说让正在运行的线程立即终止,而是通知线程你应该停止了,是否真的停止,取决于线程具体的写法
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

5.等待一个线程

线程调度是一个随机的过程,等待线程就是了控制两个线程结束的顺序
在这里插入图片描述

6.并发和并行

在这里我们讨论的都是线程,并不是进程
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值