多线程(基础)

1、认识线程

(1)概念

线程是被包在进程中的。一个进程默认会有一个线程【主线程】,但也可以有多个线程。

一个线程就是一个执行流,可以单独的在CPU上进行调度。

同一个进程中的各个线程,共享一份系统资源(内存+文件),节省了资源分配的开销

举个例子,一家公司要去银行办理业务,既要进行财务转账,又要交社保。如果只有一个会计,耗费时间长。为了让业务更快完成,该会计又喊来一位助手帮助他。两人分别负责一个事情,分别申请一个号码进行排队;此时就有两个执行流共同完成任务。本质都是办理一个公司的业务。其中,该会计是主线程。

多线程:将一个大人物分解成不同的小任务,交给不同的执行流去排队执行。

(2)线程的意义

->首先,并发编程成为刚需。单核CPU的发展遇到瓶颈,想要提高算力,就需要多核CPU。而并发编程能够充分利用多核CPU资源。

->虽然多进程也能实现并发编程,但是线程比进程更轻量。创建线程、调度线程、销毁线程都比创建进程、调度进程、销毁进程快。在创建第一个线程时,已经申请了系统资源,所以在后续创建新的线程,都是共用一份系统资源,节省了申请系统资源的开销。

(3)进程与线程的区别 

 ->首先,进程包含线程。每个进程中至少包含一个线程,即主线程。【一组PCB来描述一个进程,每个PCB对应一个线程】

->其次,线程比进程更轻量。创建线程、调度线程、销毁线程都比创建进程、调度进程、销毁进程快。

->主要的,进程之间不能共享内存空间等资源,而一个进程中的不同线程可以共享同一份内存空间。【这一组PCB上,内存指针与文件描述符表是共享的同一份;状态,优先级,上下文等是每个线程独自有一份】

->进程是系统分配资源的最小单位,线程是系统调度的最小单位。

 2、创建线程

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

 

 在第2步中,创建CreatThread类的实例时,并不会创建一个线程。只有当thread.start()执行之后,才会创建一个新的线程,然后执行run()中的逻辑代码,知道执行完,新创建的线程就会运行结束。

值得注意的是,Main主线程和CreatThread创建出来的新线程,是并发执行的关系。

 多线程中,线程的 调度,其实是随机的。->抢占式执行

 方法2:实现Runnable接口,重写run()

 

 方法3:使用匿名内部类,创建Thread子类对象

  方法4:使用匿名内部类,创建Runnable子类对象

 

 多线程的优势:能够更充分的利用多核CPU,提高程序效率。

 3、Thread 类及常见方法

        Thread 类是 JVM 用来管理线程的一个类,也即每个线程都有一个唯一的 Thread 对象与之关联。

 (1)Thread 的常见构造方法

Thread()     ----> 创建线程对象

 Thread(Runnable target)    ---->使用 Runnable 对象创建线程对象  

Thread(String name)   ----> 创建线程对象,并命名

Thread(Runnable target, String name)    ---->使用 Runnable 对象创建线程对象,并命名

Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("线程名");
Thread t4 = new Thread(new MyRunnable(), "线程名");

 (2)Thread 的几个常见属性

 ID    ---->获取方法:getId()

 名称    ---->获取方法:getName()

 状态    ---->获取方法:getState()

 优先级    ---->获取方法:getPriority()

 是否后台线程    ---->获取方法:isDaemon()

是否存活   ---->获取方法:isAlive() 

 是否被中断    ---->获取方法:isInterrupted()

注意以下几点:

-》ID是线程的唯一标识,每个线程都不同 

-》关于后台线程,JVM会在一个进程的所有非后台进程结束后,才会结束运行。

-》 关于是否存活,简单理解为 run()方法是否运行结束

 

 结果:

 (3)Thread类中run()和start()的区别

 作用功能不同:run方法,描述县城具体要执行的任务;start方法,真正申请系统线程。

 运行结果不同:run方法相当于是一个类中的普通方法,可以被调用,调用后会顺序执行一次。start被调用后,真的在操作系统底层创建出一个线程,并执行run方法中的代码,run方法执行完成后,线程进入销毁阶段。

4、中断一个线程

 就是控制线程结束,本质是让run方法尽快结束,而不是执行一半,强制结束。

 方法1:自定义一个标志位,作为线程是否结束的标志

 

 

 方法2:使用标准库中自带的一个标志位

(1)操作
使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替自定义标志位。

使用 thread 对象的 interrupted() 方法通知线程结束.   

Thread 内部包含了一个 boolean 类型的变量作为线程是否被中断的标记。 

方法:

 

 (2)分析

 interrupt方法的行为,有两种

当t线程处在运行状态,会设置标志位为true;

当t线程处于阻塞状态则以 InterruptedException 异常的形式通知,该异常会把sleep提前唤醒;出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择忽略这个异常, 也可以跳出循环结束线程

thread 可以通过:
Thread.interrupted() 判断当前线程的中断标志被设置, 清除中断标志
Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置, 不清除中断标志

 

 (3)观察标志位是否清除

标志位是否清除, 就类似于一个开关.
Thread.isInterrupted() 相当于按下开关 , 开关自动弹起来 . 这个称为 " 清除标志位"
Thread.currentThread().isInterrupted() 相当于按下开关之后 , 开关弹不起来 , 这个称为 " 不清除标志位 ".

5、等待一个线程 -join()

 控制线程之间的结束顺序。

上述,让main线程阻塞等待。等到t线程执行结束,main线程才会继续执行。

但如果是在join()之前,t线程已经结束,此时main线程不需要阻塞等待。

 方法:

 

 6、休眠当前线程

 sleep(),指定休眠时间,让线程阻塞一会

 擦偶走系统管理这些线程的PCB时,是有多个链表。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值