JAVA多线程详解(超详细)-程序员宅基地

技术标签: 面试  python  java  阿里巴巴资料职业发展  后端  学习路线  开发语言  

目录

一、线程简介

1、进程、线程

  • 程序:开发写的代码称之为程序。程序就是一堆代码,一组数据和指令集,是一个静态的概念。
  • 进程(Process):将程序运行起来,我们称之为进程。进程是执行程序的一次执行过程,它是动态的概念。进程存在生命周期,也就是说程序随着程序的终止而销毁。进程之间是通过TCP/IP端口实现交互的。
  • 线程(Thread):线程是进程中的实际运作的单位,是进程的一条流水线,是程序的实际执行者,是最小的执行单位。通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程。线程是CPU调度和执行的最小单位。
    注意:很多多线程都是模拟出来的,真正的多线程是指有多个CPU,即多核,如服务器,如果是模拟出来的多线程,即一个CPU的情况下,在同一个时间点,CPU只能执行一个代码,因为切换的很快,所以就有同时执行的错觉。

2、并发、并行、串行

  • 并发:同一个对象被多个线程同时操作。(这是一种假并行。即一个CPU的情况下,在同一个时间点,CPU只能执行一个代码,因为切换的很快,所以就有同时执行的错觉)。
  • 并行:多个任务同时进行。并行必须有多核才能实现,否则只能是并发。
  • 串行:一个程序处理完当前进程,按照顺序接着处理下一个进程,一个接着一个进行。

3、进程的三态

进程在运行的过程中不断的改变其运行状态。通常一个运行的进程必须有三个状态,就绪态、运行态、阻塞态。

  • 就绪态:当进程获取出CPU外所有的资源后,只要再获得CPU就能执行程序,这时的状态叫做就绪态。在一个系统中处于就绪态的进程会有多个,通常把这些排成一个队列,这个就叫就绪队列。
  • 运行态:当进程已获得CPU操作权限,正在运行,这个时间就是运行态。在单核系统中,同一个时间只能有一个运行态,多核系统中,会有多个运行态。
  • 阻塞态:正在执行的进程,等待某个事件而无法继续运行时,便被系统剥夺了CPU的操作权限,这时就是阻塞态。引起阻塞的原因有很多,比如:等待I/O操作、被更高的优先级的进程剥夺了CPU权限等。

二、线程实现

1、继承Thread类

 步骤:
 - 自定义线程类继承Thread类
 - 重写run()方法,编写线程执行体
 - 创建线程对象,调用start()方法启动线程(启动后不一定立即执行,抢到CPU资源才能执行)

代码如下(示例):

// 自定义线程对象,继承Thread,重写run()方法
public class MyThread extends Thread {

    public MyThread(String name){
        super(name);
    }

    @Override
    public void run() {
        // 线程执行体
        for (int i = 0; i < 10; i++) {
            System.out.println("我是自定义" + Thread.currentThread().getName() + "--" + i);
        }
    }

    public static void main(String[] args) {
        // main线程,主线程

        // 创建线程实现类对象
        MyThread thread = new MyThread("线程1");
        MyThread thread2 = new MyThread("线程2");
        // 调用start()方法启动线程
        thread.start();
        thread2.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("我是主线程--" + i);
        }
    }
}


执行结果:


我是自定义线程2--0
我是自定义线程2--1
我是主线程--0
我是自定义线程1--0
我是主线程--1
我是主线程--2
我是自定义线程2--2
我是主线程--3
我是自定义线程1--1
我是主线程--4
我是主线程--5
我是主线程--6
我是主线程--7
我是主线程--8
我是主线程--9
我是自定义线程2--3
我是自定义线程1--2
我是自定义线程2--4
我是自定义线程1--3
我是自定义线程1--4
我是自定义线程1--5
我是自定义线程1--6
我是自定义线程1--7
我是自定义线程1--8
我是自定义线程1--9
我是自定义线程2--5
我是自定义线程2--6
我是自定义线程2--7
我是自定义线程2--8
我是自定义线程2--9

2、实现Runnable接口

 步骤:
 - 自定义线程类实现Runnable接口
 - 实现run()方法,编写线程体
 - 创建线程对象,调用start()方法启动线程(启动后不一定立即执行,抢到CPU资源才能执行)

代码如下(示例):

// 自定义线程对象,实现Runnable接口,重写run()方法
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 线程执行体
        for (int i = 0; i < 10; i++) {
            System.out.println("我是自定义" + Thread.currentThread().getName() + "--" + i);
        }
    }

    public static void main(String[] args) {
        // main线程,主线程

        // 创建实现类对象
        MyRunnable myRunnable = new MyRunnable();
        // 创建代理类对象
        Thread thread = new Thread(myRunnable,"线程1");
        Thread thread2 = new Thread(myRunnable,"线程2");
        // 调用start()方法启动线程
        thread.start();
        thread2.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("我是主线程--" + i);
        }
    }
}

执行结果:

我是主线程--0
我是自定义线程1--0
我是自定义线程2--0
我是自定义线程1--1
我是主线程--1
我是自定义线程1--2
我是自定义线程2--1
我是自定义线程1--3
我是主线程--2
我是主线程--3
我是自定义线程1--4
我是自定义线程2--2
我是自定义线程2--3
我是自定义线程2--4
我是自定义线程1--5
我是自定义线程1--6
我是主线程--4
我是自定义线程1--7
我是自定义线程1--8
我是自定义线程1--9
我是自定义线程2--5
我是自定义线程2--6
我是自定义线程2--7
我是自定义线程2--8
我是主线程--5
我是自定义线程2--9
我是主线程--6
我是主线程--7
我是主线程--8
我是主线程--9

3、实现Callable接口(不常用)

 步骤:
 - 实现Callable接口,先要返回值类型
 - 重写call()方法,需要抛出异常
 - 创建目标对象
 - 创建执行服务:ExecutorService ser = Executor.newFixedThreadPool(1);
 - 提交执行:Future<Boolean> res = ser.submit(t1);
 - 获取结果:boolean r1 = res.get();
 - 关闭服务:ser.shutdownNow();

代码如下(示例):

import java.util.concurrent.*;

// 自定义线程对象,实现Callable接口,重写call()方法
public class MyThread implements Callable<Boolean> {

    @Override
    public Boolean call() throws Exception {
        // 线程执行体
        for (int i = 0; i < 10; i++) {
            System.out.println("我是自定义" + Thread.currentThread().getName() + "--" + i);
        }

        return true;
    }

    public static void main(String[] args) throws ExecutionException,
        InterruptedException {
        // main线程,主线程

        // 创建线程实现类对象
        MyThread thread = new MyThread();
        MyThread thread2 = new MyThread();

        // 创建执行服务,参数是线程池线程数量
        ExecutorService ser = Executors.newFixedThreadPool(2);
        // 提交执行
        Future<Boolean> res = ser.submit(thread);
        Future<Boolean> res2 = ser.submit(thread2);
        // 获取结果
        boolean r1 = res.get();
        boolean r2 = res2.get();
        // 关闭服务
        ser.shutdownNow();
    }
}


执行结果:


我是自定义pool-1-thread-1--0
我是自定义pool-1-thread-2--0
我是自定义pool-1-thread-1--1
我是自定义pool-1-thread-1--2
我是自定义pool-1-thread-1--3
我是自定义pool-1-thread-1--4
我是自定义pool-1-thread-1--5
我是自定义pool-1-thread-2--1
我是自定义pool-1-thread-1--6
我是自定义pool-1-thread-2--2
我是自定义pool-1-thread-2--3
我是自定义pool-1-thread-2--4
我是自定义pool-1-thread-2--5
我是自定义pool-1-thread-2--6
我是自定义pool-1-thread-2--7
我是自定义pool-1-thread-2--8
我是自定义pool-1-thread-2--9
我是自定义pool-1-thread-1--7
我是自定义pool-1-thread-1--8
我是自定义pool-1-thread-1--9

三、线程常用方法

1、线程的状态

  • 新建状态(NEW):线程已创建,尚未调用start()方法启动之前。
  • 运行状态(RUNNABLE):线程对象被创建后,调用该对象的start()方法,并获取CPU权限进行执行。
  • 阻塞状态(BLOCKED):线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
  • 等待状态(WAITING ):等待状态。正在等待另一个线程执行特定动作来唤醒该线程的状态。
  • 超时等待状态(TIME_WAITING):有明确结束时
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_74823434/article/details/133744388

智能推荐

3dmax渲染有噪点的六大原因及解决方案_3dmax噪点多怎么解决-程序员宅基地

文章浏览阅读261次。原因:环境阻光(AO)的设置不当,导致模型结构转变处产生过多的暗部阴影,从而使渲染图像呈现出颗粒感和模糊。原因:3dmax中的材质细分不够,影响渲染效果,导致图像出现颗粒感和噪点。原因:3dmax中的图像尺寸过低,导致渲染后的效果图呈现出颗粒感和噪点。原因:发光贴图和灯光缓存的设置不当,导致渲染图像出现颗粒感和噪点。原因:3dmax中的主光源灯光细分不够,导致渲染图像有颗粒感。原因:DMC采样的参数设置不合理,导致渲染图像出现噪点。按照这些设置,通常可以避免图像出现噪点。,从而避免渲染后的模糊和噪点。_3dmax噪点多怎么解决

前端渲染CSR和SSR的结合使用分析_next同时使用ssr与csr-程序员宅基地

文章浏览阅读1.2k次。我们都知道,以往的CSR(客户端浏览器渲染)多多少少会有一点点SEO问题,不只是SPA(单页面应用程序),只不过SPA的SEO问题比较严重,一般的前端项目有很多个页面,渲染的压力是分散的,所以页面渲染速度很快,基本够爬虫抓到很多内容,但SPA只有一个页面。而我们的SSR(服务器渲染)可以弥补像SPA项目的SEO(搜索引擎优化) 不友好问题。但是它本身对比CSR也是有不足的。所以,为什么不可以结合它们两个的优点去进行使用呢?_next同时使用ssr与csr

2022-IOS-For-Fun_um-ios 2022-程序员宅基地

文章浏览阅读503次。2022 IOS Developer for funBasic stuffComputer Science fundamentalsMain parts of a computer system - CPU, memory, storageHow Operating System worksWhat is a databaseHow Internet worksGit version controlObject Oriented ProgrammingThe setupMacOSHomeb_um-ios 2022

PHP中的循环描述错误有哪些_PHP关于while循环中修改选取条件出现的错误-程序员宅基地

文章浏览阅读109次。业务需求是:读取某个表中每一行的的字段A、B、C的值如果C的值是0,就改成1或者2代码大概是这么写的:$query = "SELECT * FROM table WHERE C = 0";$result = mysqli_query($link, $query);if($result){while ($rows = mysqli_fetch_array($result)){if (判断条件为tru..._while循环报错php

ionic介绍-程序员宅基地

文章浏览阅读3.4k次。最近公司在使用ionic做混合APP,虽然是最后端,但是也查一下东西,介绍一下吧这是菜鸟教程的Ionic一.介绍ionic是一种老式的使用H5开发iOS和Android应用的方式,也可以使用新的语言React Native开发,当然对于H5实现复杂的或者交互性没有那么好的,就可以使用iOS和Android的插件实现;二.Ionic特点a.开发方面:1.ionic 基于Angular..._ionic

C/C++ 用什么软件编程_c++编程软件-程序员宅基地

文章浏览阅读3.7k次,点赞2次,收藏8次。Lightly​ 是一款全平台都通用、轻量且功能强大的在线编辑器,用户不需要配置任何编译运行环境,选择开发语言后即可开始写代码。代码和项目文件可以实时保存在云端的,换台不同系统的电脑或者是用平板,也可以打开项目,继续编码。它还具备项目一键分享功能,对于有团队协作需求的开发者来说,是最合适的选择。_c++编程软件

随便推点

vue基于element-ui的Select选择器实现的动态多级联动下拉选择_element-ui select 级联-程序员宅基地

文章浏览阅读2w次,点赞6次,收藏26次。demo地址代码如下:Html<div id="app"> <el-select v-for="(arrItem,key) in selectList" :key="key" v-model="selectArr[key]" filterable placeholder="请选择" value-key="value" @change="selected" @focu..._element-ui select 级联

LeetCode——76. 最小覆盖子串_leetcode最小覆盖子串-程序员宅基地

文章浏览阅读123次。76. 最小覆盖子串_leetcode最小覆盖子串

Oracle 常用语句_oracle查询导入目录常用语句-程序员宅基地

文章浏览阅读112次。https://download.csdn.net/download/u014096024/21109113oracle练习1.如何查询一个角色包括的权限 a.一个角色包含的系统权限 select * from dba_sys_privs where grantee='DBA'; b.一个角色包含的对象权限2.oracle究竟有多少种角色 (查询oracle中所有的角色,一般是dba) select * from dba_roles;3.查询o..._oracle查询导入目录常用语句

数据可视化之美:经典案例与实践解析_数据可视化经典-程序员宅基地

文章浏览阅读9.3k次,点赞25次,收藏93次。随着DT时代的到来,传统的统计图表很难对复杂数据进行直观地展示。这几年数据可视化作为一个新研究领域也变得越来越火。成功的可视化,如果做得漂亮,虽表面简单却富含深意,可以让观测者一眼就能洞察事实并产生新的理解。可视化(visualization)和可视效果(visual)两个词是等价的,表示所有结构化的信息表现方式,包括图形、图表、示意图、地图、故事情节图以及不是很正式的结构化插图。基本的可视化展..._数据可视化经典

8086汇编4位bcd码_[走近FPGA]之二进制转BCD码-程序员宅基地

文章浏览阅读1.3k次。注:本文由不愿透露姓名的 @Bulingxx 撰写。以下为正文。在上一篇文章中介绍了数码管如何在FPGA开发板上实现动态显示,其文章链接如下:人生状态机:[走近FPGA]之数码管动态显示​zhuanlan.zhihu.com本文的所有实例都使用硬木课堂Xilinx Aritx 7 FPGA板实现,且附有上板演示视频,该开发板的链接如下:硬木课堂 Xilinx Aritx 7 FPGA板 Arm C..._8086汇编语言 实现二进制数到bcd码的转换

使用nfs之后初始化mysql失败_influxdb数据库 nfs存储初始化失败-程序员宅基地

文章浏览阅读1.7k次。将nfs作为mysql的数据目录输出后,在另一台主机上启动mysql进程时,会出现如下这样的错误,究其原因,其实还是nfs自身设计的缺陷。 初始化就是使用特定的用户,去特定的目录去更新mysql,虽然说添加mysql用户之后,所有的对数据的修改权限都是以mysql用户执行的,而且nfs的数据目录也都设计成了mysql,常理是没有问题的。但是,执行mysql_ins_influxdb数据库 nfs存储初始化失败

推荐文章

热门文章

相关标签