java多线程——线程的概念和创建(代码片段)

爱敲代码的三毛 爱敲代码的三毛     2023-01-29     444

关键词:


一、进程

关于进程更详细的介绍可以看一下上一篇博客 计算机的工作原理,这里的进程只是概括一下

一个运行起来的程序,就是一个进程,进程在操作系统中是这样进行管理:

  1. 描述PCB(pid,内存指针,文件描述符,进程的状态,上下文,优先级,记账信息,等…),实际上PCB是一个非常大的结构体,属性非常非常多。
  2. 组织:进程使用双向链表来组织

虚拟地址空间:让进程和进程之间隔离开,尽量不相互影响

引入进程的目的,就是为了能够 “并发编程”,虽然多进程已经能够解决并发的问题了,但是大佬们认为还不够理想。

  1. 创建进程,就需要分配资源
  2. 销毁进程,就需要释放资源

如果频繁创建销毁,这样的开销就比较大了

于是程序员就发明了一个 “线程(Thread)”概念,线程在有些系统上也叫做"轻量级进程"

二、线程

1.线程的概念

一个线程就是一个 “执行流”. 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之间 “同时” 执行着多份代码.并发编程,线程比进程更轻量

1. 创建线程比创建进程更高效
2. 销毁线程比销毁进程更高效
3. 调度线程比调度进程更高效

创建线程,并没有取申请资源。
销毁线程,也不需要释放资源。
线程是产生在进程内部,共用之前的资源

2.进程和线程的关系

进程和线程之间,是包含关系

一个进程可以包含一个线程或者多个线程
先把进程创建出来之后,这个时候相当于资源都分配好了
然后再在这个进程里面,创建线程,这样线程就和之前的进程共用一样的资源了

站在系统内核的角度,来看待进程和线程的话

其实在操作系统内核的角度,不分线程还是进程的,只认PCB
当创建一个进程的时候,就是创建了一个PCB出来了
同时这个PCB也可以视为是当前进程中已经包含了一个线程了(一个进程中至少得有一个线程)

属于同一个进程的线程之间是可以共用同一份内存空间,同时其它的进程(PCB)使用的是独立的内存空间

3.进程和线程之间的区别和联系

  1. 进程是包含线程的,一个进程里面可以有一个线程,也可以有多个线程。
  2. 每个进程都有独立的内存空间(虚拟地址空间),同一个进程的多个线程之间,共用这个虚拟地址空间
  3. 进程是操作系统资源分配的基本单位,线程是操作系统调度执行的基本单位

三、Java中的线程

1.线程的创建方式

在Java中使用 Thread 这个类来创建线程,通过这个类有很多方法来创建一个线程

  1. 继承 Thread 重写 run 方法
class MyTread1 extends Thread 
    @Override
    public void run() 
        System.out.println("继承Thread,重写run");
    

  1. 实现 Runnable 接口,重写run
class MyThread2 implements Runnable 
    @Override
    public void run() 
        System.out.println("实现 Runnable 接口,重写run");
    

public class TestThread2 
    public static void main(String[] args) 
        Thread t = new MyThread();
    

  1. 继承 Thread ,重写run方法,使用匿名内部类
public static void main(String[] args) 
        Thread t = new Thread() 
            @Override
            public void run() 
                super.run();
            
        ;
    
  1. 实现 Runnable,重写 run,使用匿名内部类
public static void main(String[] args) 
        Thread t = new Thread(new Runnable() 
            @Override
            public void run() 
                System.out.println("实现Runnable 接口,使用匿名内部类创建");
            
        );
    
  1. 使用 lambda 表达式
public static void main(String[] args) 
        //Thread t = new Thread(()-> System.out.println("使用 lambda 表达式来创建 Runnable 子类对象"));
        Thread t = new Thread(()->
            System.out.println("使用 lambda 表达式来创建 Runnable 子类对象");
        );
    

以上这些创建线程的方式,本质都相同。
都是借助 Thread 类,在内核中创建新的PCB,加入到内核的双向链表中
只不过区别是,指定线程要执行任务的方式不一样,
此处的区别,其实都只是单纯的Java语法层面的区别

2.start() 和 run()的区别

我们可以通过 start()方法来启动线程

public static void main(String[] args) 
        Thread thread = new Thread(new Runnable() 
            @Override
            public void run() 
                System.out.println("启动线程");
            
        );
        thread.start();
    

我们直接调用 run 方法

public static void main(String[] args) 
        Thread thread = new Thread(new Runnable() 
            @Override
            public void run() 
                System.out.println("启动线程");
            
        );
        thread.run();
    

这两者的运行结果都是有相同的

那么它们到底有什么区别呢?

start() 方法
当点击运行时,首先系统会创建一个进程,这个进程里面包含了一个线程,就是main方法,接着运行 start方法,会创建一个新的PCB也就是线程,挂在链表上。
接着这个新的PCB会执行相应代码


run() 方法,直接运行并没创建新的线程

总结:start会创建一个新的线程执行run方法,同时main方法同时执行。run方法和main方法属于同一进程,是并发执行的。

run方法不会创建新的进程,相当于一个普通的方法。直接调用 run 方法还是顺序执行状态,只有当
run方法执行完后才会执行下面的代码。并没有达到多线程的目的

3.jconsole

在 Java jdk 的 bin 目录下有 jconsole 的工具,可以查看到进程的


当线程跑起来后之后打开,找到对应的线程。


4.多线程的好处

假设我们对两个个变量同时自增 20 亿次

采用串行执行

public static void main(String[] args) 
        long a = 0;
        long b = 0;
        long start = System.currentTimeMillis();
        for (long i = 0; i < count; i++) 
            a++;
        
        for (long i = 0; i < count; i++) 
            b++;
        
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    

运行结果

采用并发执行

private static final long count = 10_0000_0000L;

    public static void main(String[] args) 
        long start = System.currentTimeMillis();
        Thread t1 = new Thread(new Runnable() 
            long a = 0;
            @Override
            public void run() 
                for (int i = 0; i < count; i++) 
                    a++;
                
            
        );
        Thread t2 = new Thread(new Runnable() 
            long b = 0;
            @Override
            public void run() 
                for (long i = 0; i < count; i++) 
                    b++;
                
            
        );
        t1.start();
        t2.start();
        //阻塞,只有当 t1和t2执行完才执行后面的代码
        try 
            t1.join();
            t2.join();
         catch (InterruptedException e) 
            e.printStackTrace();
        
        long end = System.currentTimeMillis();
        System.out.println(end-start);
    

运行结果


我们发现多线程的确快了不少,

串行执行:700mm左右
并发执行:400mm左右

那么是正好300的差距吗?不一定的,

线程调度,自身也是有开销的。

一个线程执行 40 亿次和两个线程各执行 20 亿次,中间都可能会调度诺干次,也就是都会花一定时间,这个时间是不确定的


下一篇线程的Thread 类及常见方法

java_多线程(代码片段)

...Java_基本概念Java_单核和多核的理解Java_并行与并发Java_多线程Java_线程的创建和使用Java_Thread类Java_创建线程的两种方式Java_基本概念程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静... 查看详情

java线程教程:使用java创建线程和多线程(代码片段)

与许多其他计算机语言不同,Java提供了对多线程的内置支持。Java中的多线程包含两个或多个可以同时运行的部分。Java线程实际上是一个轻量级进程。本文将介绍许多人发现棘手或难以理解的JavaThread概念。 我将讨论以下主... 查看详情

java多线程简介和简单使用(代码片段)

Java多线程简介1.线程简介1.1.线程概念1.2.进程概念1.3.线程作用1.4.进程和线程的联系2.线程执行2.1.示例2.2.解释2.3.线程在内存中的分配2.4.创建线程2.4.1.继承Thread类2.4.2.实现Runnable接口2.4.3.对比3.前台线程和后台线程1.线程简介1.1.线... 查看详情

java基础知识点笔记总结(代码片段)

文章目录1.IntellijIDEA软件使用2.多线程的概念3.方式一继承Thread线程3.1继承Thread创建线程3.2Thread方式两个问题3.3Thread匿名对象创建线程3.4Thread类常用的方法3.5线程的调度4.方式二实现Runnable接口创建多线程5.两种创建多线程方式的对... 查看详情

多线程--线程的创建与启动(代码片段)

创建一个线程,Java提供三种方法(1)通过实现Runnable接口,重写run方法(2)通过继承Thread类本身,--必须重写(3)通过Callable和Future创建线程Thread类的方法voidstart()使该线程开始执行,Java虚拟机调用该线程的run方法。finalvoidsetNa... 查看详情

java多线程-创建线程方式1:继承thread类,重写run()方法,调用start开启线程(代码片段)

...是系统资源分配的单位通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是CPU调度和执行的 查看详情

java多线程:线程池详解(代码片段)

文章目录1.线程池1.1线程池概述1.1.1线程池的概念1.1.2线程池的工作机制1.1.3使用线程池的原因1.1.3线程池的设计思路:1.2线程池的创建1.2.1Executors默认线程池newCachedThreadPool:创建默认线程池,最多容纳int类型的最大值newFixedT... 查看详情

java多线程(代码片段)

多线程进程其他相关概念创建线程的两种方式为什么使用start()方法而不直接使用run()方法start()方法底层继承Thread和实现Rnnable的区别售票系统SellTicket01类继承Thread实现SellTicket02类实现Runnable接口线... 查看详情

linux多线程(代码片段)

线程一、Linux线程概念1、什么是线程2、原生线程库pthread3、线程的优点4、线程的缺点5、线程异常6、线程的用途二、Linux进程VS线程1、进程和线程2、进程的多个线程共享3、进程和线程的区别三、POSIX线程库1、线程创建2、线程等... 查看详情

java多线程编程--线程安全和锁synchronized概念(代码片段)

##一、进程与线程的概念##(1)在传统的操作系统中,程序并不能独立运行,作为资源分配和独立运行的基本单位都是进程。在未配置OS的系统中,程序的执行方式是顺序执行,即必须在一个程序执行完后&#... 查看详情

多线程——java线程池简介(代码片段)

      上次我们回忆了多线程的基础概念,今天,我们来看看Java中对线程池的使用。一、线程池1、为什么需要      在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或... 查看详情

java篇多线程详解(代码片段)

...xff01;经过一个阶段的学习,Java基础知识学习终于到多线程了!Java多线程以及后面互斥锁的概念都是Java基础学习的难点,所以我做了一个总结,希望对大家也有帮助! 下面开始学习Java多线程吧!目录1.线... 查看详情

java多线程与并发(案例+应用)(代码片段)

文章目录1.传统创建线程的两种方式2.传统定时器技术3.传统线程互斥技术4.传统线程同步通信技术5.线程范围内共享变量概念和作用6.ThreadLocal类及应用技巧7.多个线程之间共享数据的方式8.Java原子性类的应用9.Java线程并发库的应... 查看详情

java多线程编程从入门到卓越(超详细总结)(代码片段)

导读:java多线程编程不太熟?或是听说过?或是想复习一下?找不到好的文章?别担心我给你们又安利一波,文章内容很全,并且考虑到很多开发中遇到的问题和解决方案。循环渐进,通俗易懂,文章较长,建议收藏再看!往... 查看详情

java进阶——线程基础(代码片段)

线程基础1、线程介绍1.1、线程相关概念程序(program):是完成特定任务,用某种语言编写的一组的集合(例如:java代码就是一个程序)进程:是指运行中的程序(比如:我现在使用的Typora)进程是程序的一次执行过程是动态的... 查看详情

01多线程概念及其实现方式(代码片段)

多线程是编程过程里必不可少的内容,学习多线程,就先要了解进程和线程的概念。进程:是指当前正在运行的程序,是一个程序在内存里的执行区域;线程:是在进程里的一个执行控制单元,执行路径; 实现多线程的方式... 查看详情

尚硅谷_java零基础教程(多线程)--学习笔记(代码片段)

Java多线程一、基本概念1、程序、进程、线程2、单核CPU和多核CPU、并行与并发3、使用多线程的优点二、线程的创建和使用1、API中创建线程的两种方式1.1、方式一:继承Thread类1.2、方式二:实现Runnable接口1.3、Thread类的调... 查看详情

java基础多线程概念(代码片段)

多线程中的基础概念CPU核心数和线程数的关系提及目前广泛的计算机设备,无论是电脑还是手机,都离不开一个设备CPU;CPU是一个需要考虑的核心因素,因为它决定了电脑或者手机的性能等级。CPU从早期的单核... 查看详情