线程基本概念和创建

线程的概念

一个线程就是一个"执行流",一个进程中至少有一个线程,每个线程运行自己的代码块,多个线程会同时运行多段代码。

线程的意义

如果把进程比作银行的服务,张三(即用户)来接受服务时必然要经过不同程序,例如身份查询、业务解释、业务办理等等,一个线程就相当于一个工作人员,而多线程就相当于多个工作人员为张三处理事务,每个工作人员同时分工合作,这样就大大提高了工作效率,这也就是所谓的并发编程。

并发编程在狭义上指的是一个CPU核心运行多个线程,与之对应的还有并行——指n个CPU核心运行n个线程,但是我们常说的并发编程广义上包括了并发和并行。

并发编程充分利用了多核CPU的性能,从而更能发挥CPU的运算效率。

同时,线程相比于进程更轻量化,创建和销毁一个线程的速度远大于创建和销毁一个进程的速度。对于一个进程来说,它的创建和销毁有如下步骤:

创建

  1. 创建PCB
  2. 给进程分配资源(内存、文件),赋给PCB
  3. 把PCB插入链表

销毁

  1. 把PCB从链表移除
  2. 释放PCB中的资源
  3. 销毁PCB

其中给进程分配资源和销毁资源极大占用了操作系统的资源,因此效率较低。

以之前的银行服务为例,如果一个银行同时遇到多个客户就必须开辟多个进程然后销毁,这就大大浪费了时间。

而一个进程上的多个线程是共享同一份资源的,直到最后一个线程被销毁,这个进程的资源才被释放,所以极大节约了系统资源。

线程和进程的区分

操作系统中是通过一组PCB来描述一个进程的,其中每个PCB对应一个线程。

因此一个进程至少有一个线程,线程是被包含在进程中的。

由于线程共享资源,一组PCB的内存指针和文件描述符表其实是同一份东西,而状态、上下文、优先级、记账信息则是每个PCB独有的。

总的来说:

进程是资源分配的单位

线程是调度执行的单位

线程的创建

Thread类的构造

java实现了操作多线程的API,想要实现多线程只需要调用API即可,而Thread类就是java提供的API。

创建Thread类的方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用 Runnable 对象创建线程对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target, String name)使用 Runnable 对象创建线程对象,并命名

获取Thread类的属性方法

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()
  • ID 是线程的唯一标识,不同线程不会重复

  • 名称是各种调试工具用到

  • 状态表示线程当前所处的一个情况

  • 优先级高的线程理论上来说更容易被调度到

  • 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。

  • 是否存活,即简单的理解,为 run 方法是否运行结束了

  • 线程的中断问题,下面我们进一步说明

通过继承Thread对象重写run方法
class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(1);
        }
    }
}

MyThread t = new MyThread();
通过Runnable接口重写run方法传递给Thread对象

使用Runnable接口可以减少代码的耦合性,即要修改Thread的功能只需要修改对应的Runnable接口或者放入新的Runnable接口

class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(1);
        }
    }
}

Thread t = new Thread(new MyRunnable());
匿名内部类
//继承Thread类 
Thread t = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(1);
                }
            }
        };
lambda表达式
Thread t = new Thread(() -> {
    for (int i = 0; i < 10; i++) {
        System.out.println(1);
        }
    }

多线程的缺点

线程让程序更有效率的同时也给程序猿带来了很多问题,这些问题往往伴随着它们的优势。

  1. 我们知道多个线程公用同一份资源,同时运行,这就不可避免导致了多个线程同时操作同一份资源的情况,产生一系列如脏读、幻读、不可重复读等问题,为了解决这些问题就必须以效率为代价对线程的权限加以限制,即为线程“上锁“,具体方法会在下篇博客中阐述。

  2. 线程产生的问题难以修复。线程的调度是由操作系统决定的,因此线程执行的顺序是不可预料的,这就给多线程程序的执行带来了太多的变数。所以如果代码产生了问题,由于顺序的不确定性,可能每次运行会产生不同的结果,甚至有可能有的时候运行结果是对的,有的时候会错,这就为调试增加了难度。如果要编写多线程代码,程序猿就必须考虑所有可能的调度情况,保证每种情况都不出现问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

最后一只三脚兽

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

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

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

打赏作者

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

抵扣说明:

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

余额充值