多线程程序将单个任务按照功能分解成多个子任务来执行,每个子任务称为一个线程,多个线程共同完成主任务的运行过程,这样可以缩短用户等待时间,提高服务效率。本篇博客将简单介绍Java开发中多线程的使用。
目录:
☍ 程序、进程、线程基本概念
▾ 程序、进程、线程概念
程序(program)
☃ 程序是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
进程(process)
☃ 进程(process)是程序的一次执行过程,或是正在运行的一个程序。进程是一个动态的过程:有它自身的产生、存在和消亡的过程——生命周期
↝ 如运行中的音乐播放器,运行的QQ
↝ 程序是静态的,进程是动态的
↝ 进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域
线程(thread)
☃ 进程可进一步细化为线程,是一个程序内部的一条执行路径。
↝ 若一个进程同一时间并行执行多个线程,称之为多线程运行
↝ 线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销较小
↝ 一个进程中的多个线程共享相同的内存单元/内存地址空间(它们从同一堆中分配对象),可以访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源可能会带来安全隐患。
☃ 一个Java应用程序java.exe,至少有三个线程:main()主线程,gc()垃圾回收线程,异常处理线程。当然如果发生异常,会影响主线程。
单核CPU和多核CPU概念
☃ 单核CPU,其实是一种假的多线程,因为在一个时间单元内,也只能执行一个线程的任务(线程交替执行)。例如:有多车道(对应多线程)最终汇聚到一个收费站口(对应cpu),只有前面的车付完过路费(一个线程执行完毕),后面的车才能继续通过,否则就要挂起等待。
☃ 如果是多核的话,才能更好的发挥多线程的效率。多条车道,多个收费口。
并行与并发
☃ **并行:**多个CPU同时执行多个任务。比如:多个人同时做一个任务中不同的事。
☃ **并发:**一个CPU(采用时间片)同时执行多个任务。比如:网上商城秒杀活动、多个人同时做同一件事。
个人对多线程,并行,并发,cpu核数之间的理解(如果有不对的地方欢迎评论指正):
(1)cpu核数是硬件条件,核数越大程序执行速度越快。在单核cpu上是伪多线程(单元时间内只能执行一个线程),只有在多核cpu上才能更好的体现多线程的优点,换句话说多线程就是为了提高进程运行效率,提高cpu利用率。
(2)并行和并发与cpu核数的关系:并行是多个cpu同时处理不同的任务,并发是一个cpu同一时间内执行多个任务。单核严格意义上不存在并行(即使有也是伪并行);并发不论是单核还是多核都有可能发生,只要相同时间内同时有多个请求要执行某一段代码或者指令就会发生并发。
(3)多线程与并行和并发的关系:多线程与并行和并发是不同的概念。多线程不等同于并行或并发,多线程是将复杂的进程分为多个子进程运行,可以理解为多线程是为了合理的利用系统资源。如果子进程之间相互独立,并且运行时互不干扰,那么可以认为它是并行的;如果子进程在执行时同时调用一个公共资源,那么它就是并发的。
▾ 多线程优点
多线程优点
☃ 提高应用程序的响应。对图形化界面更有意义,可增强用户体验。
☃ 提高计算机系统CPU的利用率。
☃ 改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改。
多线程不一定就比单线程快,如果线程都是在一个cpu中运行,那么单线程要比多线程快,因为在一个cpu核中多线程来回交替运行需要花费更多的时间;如果是多线程在多核中运行通常就会比单线程快。
▾ 多线程的应用场景
☃ 程序需要同时执行两个或多个任务。
☃ 程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等。
☃ 需要一些后台运行的程序时。
☍ 线程的创建和使用
Java语言的JVM允许程序运行多个线程,它通过java.lang.Thread
类来体现。
jdk1.5之前提供两种Java API方式创建新执行线程
- 继承Thread类的方式
- 实现Runable接口的方式
Thread类的特点
☃ 每个线程都是通过某个特定Thread对象的run()方法来完成操作的,经常把run()方法的主体称为线程体
。
☃ 通过该Thread对象的start()方法来启动这个线程,而非直接调用run()。
Thread类的构造器
☃ Thread() :创建新的Thread对象
☃ Thread(String threadname):创建线程并指定线程实例名
☃ Thread(Runnable target) :它实现了Runnable接口中的run方法。
☃ Thread(Runnable target, String name) :指定创建线程的目标对象和线程实例名
▾ 创建新线程方式一:继承Thread类
☃ 定义子类继承Thread类。
☃ 子类中重写Thread类中的run方法。
☃ 创建Thread子类对象(即线程对象)。
☃ 调用线程对象start方法:启动线程,调用run方法。
//1、MyThread类继承Thread
class MyThread extends Thread{
// 2、重写Thread中的run()
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
if(i % 2 == 0){
System.out.println("偶数:" + i);
}
}
}
}
public class ThreadTest {
public static void main(String[] args) {
//3、创建Thread类的子类对象
MyThread thread1 = new MyThread();
//4、子类对象调用start方法
thread1.start();
for (int i =