Java多线程(一)多线程概要

news2025/4/16 18:08:28

多线程概要

多线程概要

什么是进程?

进程的特点:

什么是多线程

多线程编程:

 创建线程

1.继承 Thread 类

2.实现 Runnable 接口

多线程的优势

中断问题:

1. 通过共享的标记来进行沟通

2. 调用 interrupt() 方法来通知

等待一个线程-join()

多线程概要

什么是进程?

在冯诺依曼体系下,整个计算机设备分为,应用程序,操作系统,处理器(cpu),主存,I/O设备。应用程序在操作系统的调节下在处理器上进行合理的资源分配,而在其中一个运行起来的程序,就是进程。

cpu有一个概念,核心数和线程,核心为物理核心,线程为逻辑核心

而进程管理其实分为两步:

        1.描述一个进程:使用结构体或类,把一个进程有哪些信息,表示出来。

        2. 组织这些进程:使用一定的数据结构,把这些结构体/对象,放在一起。

进程的特点:

  1.   PID :每个进程需要有一个唯一的身份标识
  2.   内存指针:当前这个进程使用的内存是哪一部分,进程一旦开启,就会消耗一定的硬件资源
  3.  文件描述符:进程每次打卡一个文件,就会产生一个“文件描述符”  ,被标识了的意味着这个文件已打开。而一个进程会打开多个文件,然后呢就会把这些文件描述符放到循序表中,构成文件描述符表
  4. 进程调度:
  • 进程状态:就绪态,阻塞态,前者表示该进程已准备好,可以随时上cpu上执行,后者还需等待
  • 进程优先级:那个进程优先级高就先执行那个进程
  • 进程的上下文:就是描述了当前进程执行到哪里这样的“存档记录”,进程在离开CPU的时候就要把当前运行的中间结果存档在cpu的寄存器中,等到下次进程回来CPU上,在恢复之前的存档,从上次结果开始
  • 进程的记账信息:统计了每个进程,在CPU上执行了多久,可以作为调度的参考依据。
  • 并发和并行:指的是多个程序可以同时运行的现象,更细化的是多进程可以同时运行或者多指令可以同时运行。它们虽然都说是"多个进程同时运行",但是它们的"同时"不是一个概念。并行的"同时"是同一时刻可以多个进程在运行(处于running),并发的"同时"是经过上下文快速切换,使得看上去多个进程同时都在运行的现象,是一种OS欺骗用户的现象

内存分配:

        操作系统给进程分配的内存,是以“虚拟地址空间”的方式进行分配。

什么是多线程

之前说过,进程是一个运行程序,然而一个程序内的功能有很多个,而这其中就有一个问题,就是客户可能会同时用一个程序的多个功能。诺是按照以前我们的写发就是一个main方法,去实现一个主要功能,肯定是不行的。为了应对这个情况,多线程运行就在所难免。

需求决定技术发展

线程是更轻量的的进程。约定一个进程可以包含多个线程,此时多个线程每个线程都是一个独立可以调度执行的执行流(并发),这些线程公用同一份进程的系统资源。

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

可以理解为,一个工厂(进程),中有很多个生产线:(线程)(调用同一份资源,内存空间,文件描述符)。

其中几个问题要重点理解。一个厂子也就意味着资源和场地是一定的,如果为了生产效率,盲目去增加生产线,不去顾忌这些,反而会使的整个生成效率变慢。同理一个主机的核心也是有限,所以增加的线程数和进程数也是有限度。而一台主机到限度了,就可以增加另一台主机,从而使得核心数增加(也就是分布式处理)。

进程和线程的区别:

1.进程包含线程

2.进程有自己独立的内存空间和文件描述符,同一个进程的多个线程之间,共享同一份地址空间和文件描述符

3.进程是操作系统资源分配的基本单位,线程是操作系统调度的基本单位

4.进程之间具有独立性,一个进程挂了,不会影响到别的进程;同一个进程里的多个线程之间,一线程挂了,可能会把整个进程带走,会影响到其他线程的。

多线程编程:

Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进行了进一步的抽象和封装。

操作系统内核实现了线程这样的机制, 并且对用户层提供了一些 API 供用户使用(例如 Linux 的 pthread 库)

这是我们第一个多线程。

public class ThreadDemo {
    private static class MyThread extends Thread {
        @Override
        public void run() {
            Random random = new Random();
            while (true) {
                // 打印线程名称
                System.out.println(Thread.currentThread().getName());
                try {
                    // 随机停止运行 0-9 秒
 Thread.sleep(random.nextInt(10));
               } catch (InterruptedException e) {
                    e.printStackTrace();
               }
           }
       }
   }
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();
        t1.start();
        t2.start();
        t3.start();
        Random random = new Random();
        while (true) {
            // 打印线程名称
            System.out.println(Thread.currentThread().getName());
            try {
                Thread.sleep(random.nextInt(10));
           } catch (InterruptedException e) {
                // 随机停止运行 0-9 秒
                e.printStackTrace();
           }
       }
   }
}

 创建线程

1.继承 Thread
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("这里是线程运行的代码");
   }
}

  创建一个线程实例

MyThread t = new MyThread();

   调用 start 方法启动线程

t.start(); // 线程开始运行
2.实现 Runnable 接口
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("这里是线程运行的代码");
   }
}

创建 Thread 类实例, 调用 Thread 的构造方法时将 Runnable 对象作为 target 参数

Thread t = new Thread(new MyRunnable());

调用start方法

t.start(); // 线程开始运行
class MyRunnabble implements Runnable{

    @Override
    public void run() {
        while (true)
        {
            System.out.println("123__true");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class test1 {
    public static void main(String[] args) {
        MyRunnabble runnabble=new MyRunnabble();
        Thread t=new Thread(runnabble);
        t.start();
        while (true) {
            System.out.println("main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


}
  1. 继承 Thread 类, 直接使用 this 就表示当前线程对象的引用.
  2. 实现 Runnable 接口, this 表示的是 MyRunnable 的引用. 需要使用 Thread.currentThread()

常见方法:

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

常见属性:

// 使用匿名类创建 Thread 子类对象

Thread t1 = new Thread() {

   @Override

   public void run() {

       System.out.println("使用匿名类创建 Thread 子类对象");

  }

};

// 使用匿名类创建 Runnable 子类对象

Thread t2 = new Thread(new Runnable() {

   @Override

   public void run() {

       System.out.println("使用匿名类创建 Runnable 子类对象");

  }

});

// 使用 lambda 表达式创建 Runnable 子类对象

Thread t4 = new Thread(() -> {

   System.out.println("使用匿名类创建 Thread 子类对象");

});

多线程的优势

1. 增加运行速度,通过记录时间戳

        使用 System.nanoTime() 可以记录当前系统的纳秒级时间戳.

        

public class test3 {
     static int count=0;
    public synchronized static void sum(){
        count++;
    }
    public static void main(String[] args) throws InterruptedException {
        long time=System.currentTimeMillis();
        Thread t1=new Thread(()->{
                for (int i = 0; i < 10000; i++) {
                    sum();
                }
        });
        Thread t2=new Thread(()->{
            for (int i = 0; i < 10000; i++) {
                sum();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(count);
        System.out.println(System.currentTimeMillis()-time);
    }
}
  1. ID 是线程的唯一标识,不同线程不会重复
  2. 名称是各种调试工具用到
  3. 状态表示线程当前所处的一个情况,下面我们会进一步说明
  4. 优先级高的线程理论上来说更容易被调度到
  5. 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。
  6. 是否存活,即简单的理解,为 run 方法是否运行结束了
  7. 线程的中断问题,下面我们进一步说明

中断问题:

一个程序要执行很多次,可是我们突然有了一个需求要添加,就得让这个程序停下来,所以我就需要线程中断。

目前常见的有以下两种方式:

1. 通过共享的标记来进行沟通

注意变量捕获,但是java中要求变量捕获,捕获的变量的必须要final或者“实际final”及没有用final修饰,但是代码中没有做出修改。

public class ThreadDemo {
    private static class MyRunnable implements Runnable {
        public volatile boolean isQuit = false;
        @Override
        public void run() {
            while (!isQuit) {
                System.out.println(Thread.currentThread().getName()
                        + ": 转账");
                try {
                    Thread.sleep(1000);
               } catch (InterruptedException e) {
                    e.printStackTrace();
               }
           }
           
       }
   }
    public static void main(String[] args) throws InterruptedException {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target, "李四");
        System.out.println(Thread.currentThread().getName()
                + ": 让李四开始转账。");
        thread.start();
        Thread.sleep(10 * 1000);
        System.out.println(Thread.currentThread().getName()
                + ": 通知李四对方是个骗子!");
        target.isQuit = true;
   }
}
2. 调用 interrupt() 方法来通知

使用 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 代替自定

义标志位.

public class ThreadDemo {
    private static class MyRunnable implements Runnable {
        @Override
        public void run() {
            // 两种方法均可以
            while (!Thread.interrupted()) {
            //while (!Thread.currentThread().isInterrupted()) {
                System.out.println(Thread.currentThread().getName()
                        + ": 转账!");
                try {
                    Thread.sleep(1000);
               } catch (InterruptedException e) {
                    e.printStackTrace();
       
                    break;
               }
           }

       }
   }
    public static void main(String[] args) throws InterruptedException {
        MyRunnable target = new MyRunnable();
        Thread thread = new Thread(target, "李四");
        System.out.println(Thread.currentThread().getName()
                + ": 开始转账。");
        thread.start();
        Thread.sleep(1000);
        System.out.println(Thread.currentThread().getName()
                + ": 对方是个骗子!");
        thread.interrupt();
   }
}
方法说明
public void interrupt()

中断对象关联的线程,如果线程正在阻塞,则以异常方式通知, 否则设置标志位

public static boolean

interrupted()

判断当前线程的中断标志位是否设置,调用后清除标志位

public boolean

isInterrupted()

判断对象关联的线程的标志位是否设置,调用后不清除标志位

thread 收到通知的方式有两种(这种方式通知收到的更及时,即使线程正在 sleep 也可以马上收到):

1. 如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通

知,清除中断标志

  • 当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择忽略这个异常, 也可以跳出循环结束线程.

2. 否则,只是内部的一个中断标志被设置,thread 可以通过

  • Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
  • Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志

注意:interrupt():作用设置标志位true,如果该线程在阻塞中,此时会把阻塞状态唤醒,抛出异常的方式中断。(当sleep(也可看做阻塞)被唤醒会自动把interrupted,将标志位清空)

产生阻塞的方法,会使得看到标识位为true,任然会抛出异常和清空标志,如果设置interrupt的时候,阻塞巧合醒了,这个时候程序执行到下一个循环判断条件就结束了。

等待一个线程-join()

有时,我们需要等待一个线程完成它的工作后,才能进行自己的下一步工作。这样可以让线程变得可控。线程的调度是随机的,无法判定两个线程谁先结束,谁先开始。而jion就是确定谁先开始的方法。

方法说明
public void join()等待线程结束
public void join(long millis)等待线程结束,最多等 millis 毫秒
public void join(long millis, int nanos)同理,但可以更高精度
public class test2 {
    public static void main(String[] args) throws InterruptedException {
        Thread t=new Thread(){
            @Override
            public void run() {
                while (true) {

                    System.out.println("123545_run");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                    }
                }
            }
        };
        t.start();
        t.join();
        while (true) {

            System.out.println("123545_run");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

NEW: 安排了工作, 还未开始行动

RUNNABLE: 可工作的. 又可以分成正在工作中和即将开始工作.

BLOCKED: 这几个都表示排队等着其他事情

WAITING: 这几个都表示排队等着其他事情

TIMED_WAITING: 这几个都表示排队等着其他事情

TERMINATED: 工作完成了.

public class ThreadState {
    public static void main(String[] args) {
        for (Thread.State state : Thread.State.values()) {
            System.out.println(state);
       }
   }
}

BLOCKED 表示等待获取锁, WAITING 和 TIMED_WAITING 表示等待其他线程发来通知.

TIMED_WAITING 线程在等待唤醒,但设置了时限; WAITING 线程在无限等待唤醒

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/990715.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

flutter开发实战-实现自定义bottomNavigationBar样式awesome_bottom_bar

flutter开发实战-实现自定义bottomNavigationBar样式awesome_bottom_bar 在开发过程中&#xff0c;需要自定义bottomNavigationBar样式&#xff0c;可以自定义实现&#xff0c;这里使用的是awesome_bottom_bar库 一、awesome_bottom_bar 在pubspec.yaml中引入awesome_bottom_…

滑动谜题 -- BFS

滑动谜题 输入&#xff1a;board [[4,1,2],[5,0,3]] 输出&#xff1a;5 解释&#xff1a; 最少完成谜板的最少移动次数是 5 &#xff0c; 一种移动路径: 尚未移动: [[4,1,2],[5,0,3]] 移动 1 次: [[4,1,2],[0,5,3]] 移动 2 次: [[0,1,2],[4,5,3]] 移动 3 次: [[1,0,2],[4,5,3]…

前端实现展开收起的效果 (react)

需求背景&#xff1a;需要实现文本的展开收起效果&#xff0c;文本是一行一行的&#xff0c;数据格式是数组结构。 如图所示&#xff08;图片已脱敏&#xff09; 简单实现&#xff1a;使用一个变量控制展开收起效果。 展开收起逻辑部分&#xff08;react&#xff09; const […

layer is not a constructor缺少报错解决方案参考开发教程并在相关页面引入

问题场景&#xff1a; 1.在使用Mars3d热力图功能时&#xff0c;提示mars3d.layer.HeatLayer is not a constructor 问题原因: 1.mars3d的热力图插件mars3d-heatmap没有安装引用。 解决方案&#xff1a; 1.参考开发教程&#xff0c;找到相关的插件库&#xff1a;Mars3D 三维…

Power BI依据列中值的范围不同计算公式增加一列

Power BI依据列的范围不同计算公式增加一列&#xff0c;在我们遇到了依据范围不同的公式计算时&#xff0c;就可以采用下面公式 一、增加组计算公式 佣金分组 SWITCH(TRUE(), ry_vue clawer_zhuan[到手价]>0&&ry_vue clawer_zhuan[到手价]<475,80, ry_vue claw…

华为OD机考算法题:数字加减游戏

目录 题目部分 解读与分析 代码实现 题目部分 题目数字加减游戏难度难题目说明小明在玩一个数字加减游戏&#xff0c;只使用加法或者减法&#xff0c;将一个数字 s 变成数字 t 。 每个回合&#xff0c;小明可以用当前的数字加上或减去一个数字。 现在有两种数字可以用来加减…

华为云云耀云服务器L实例评测|华为云上试用主机安全产品Elkeid

文章目录 华为云云耀云服务器L实例评测&#xff5c;华为云上试用主机安全产品Elkeid一、背景&#xff1a;什么是主机安全二、主机安全之Elkeid1. Elkeid 介绍2. Elkeid Server3. Elkeid Server 架构Elkeid AgentCenter&#xff08;下面简称AC&#xff09;Elkeid Service Discov…

[构建自己的 Vue 组件库] 小尾巴 UI 组件库

文章归档于&#xff1a;https://www.yuque.com/u27599042/row3c6 组件库地址 npm&#xff1a;https://www.npmjs.com/package/xwb-ui?activeTabreadme小尾巴 UI 组件库源码 gitee&#xff1a;https://gitee.com/tongchaowei/xwb-ui小尾巴 UI 组件库测试代码 gitee&#xff1a…

Java(四)数组与类和对象

Java&#xff08;四&#xff09;数组与类和对象 六、数组&#xff08;非常重要&#xff09;1.定义2.遍历2.1遍历方法2.2Arrays方法 3.二维数组数组小总结 七、类和对象1. 定义&#xff08;重要&#xff09;1.1 类1.2 对象 2. this关键字&#xff08;重要&#xff09;2.1 特点 3…

方差分析的核心概念“方差分解“

方差是统计学中用来衡量数据集合中数值分散或离散程度的一种统计量。它表示了数据点与数据集合均值之间的差异程度&#xff0c;即数据的分散程度。方差越大&#xff0c;表示数据点更分散&#xff0c;而方差越小&#xff0c;表示数据点更集中。 方差的计算公式如下&#xff1a;…

自己开发一个接口文档页面html

演示效果 具体代码如下 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>框架框架文档页面</…

网络原理(一)网络基础,包括IP ,网络相关的定义

网络基础 以下图片是书上的网图。 什么是IP地址&#xff1f; IP地址&#xff08;Internet Protocol Address&#xff09;是指互联网协议地址&#xff0c;又译为网际协议地址。P地址是IP协议提供的一种统一的地址格式&#xff0c;它为互联网上的每一个网络和每一台主机分配一…

电商(淘宝1688京东拼多多等)API接口服务:提升商业效率和用户体验的关键

电商API接口服务&#xff1a;提升商业效率和用户体验的关键 随着电子商务的飞速发展&#xff0c;电商企业需要不断提升自身的业务能力和服务质量&#xff0c;以应对日益激烈的市场竞争。为了更好地满足商家和消费者的需求&#xff0c;电商API接口服务应运而生。本文将探讨电商…

【进阶篇】Redis内存淘汰详解

文章目录 Redis内存淘汰详解0. 前言大纲Redis内存淘汰策略 1. 什么是Redis内存淘汰策略&#xff1f;1.1.Redis 内存不足的迹象 2. Redis内存淘汰策略3. 原理4. 主动和被动1. 主动淘汰1.1 键的生存周期1.2 过期键删除策略 2. 被动淘汰2.2 被动淘汰策略的实现 5. 项目实践优化策略…

【autodl/linux配环境心得:conda/本地配cuda,cudnn及pytorch心得】-未完成

linux配环境心得&#xff1a;conda/本地配cuda&#xff0c;cudnn及pytorch心得 我们服务器遇到的大多数找不到包的问题一&#xff0c;服务器安装cuda和cudnn使用conda在线安装cuda和cudnn使用conda进行本地安装检查conda安装的cuda和cudnn本地直接安装cuda和cudnn方法一&#x…

MDK-Keil AC6 Compiler屏蔽特定警告

最近在使用STM32CubeMX生成MDK工程是&#xff0c;使用了 AC6 版本的编译器进行编译代码&#xff0c;然后发现了一些警告&#xff0c;但是在 AC5 版本下编译又正常。于是研究了下怎么屏蔽特定的警告&#xff0c;这里记录一下。 1. Keil AC6屏蔽特定警告 遇到的警告如下&#x…

CSS的break-inside 属性 的使用

break-inside 属性在 CSS 页码分隔模块中使用,它定义了一个元素内部是否允许发生页面、栏目或者区域的分隔。 break-inside有以下几个值 break-inside: avoid- 表示避免在该元素内部发生分页或者分栏。break-inside: auto - 默认允许分页break-inside: avoid-page - 避免页面…

【LeetCode题目详解】第九章 动态规划part07 70. 爬楼梯 (进阶) 322. 零钱兑换 279.完全平方数 (day45补)

本文章代码以c为例&#xff01; 一、力扣第70题&#xff1a;爬楼梯 题目&#xff1a; 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 注意&#xff1a;给定 n 是一个正整数。 示例 1&#x…

如何在 Ubuntu 上安装和使用 Nginx?

ginx&#xff08;发音为“engine-x”&#xff09;是一种流行的 Web 服务器软件&#xff0c;以其高性能和可靠性而闻名。它是许多流行网站使用的开源软件&#xff0c;包括 Netflix、GitHub 和 WordPress。Nginx 可以用作 Web 服务器、负载均衡器、反向代理和 HTTP 缓存等。 它以…

[小尾巴 UI 组件库] 全屏响应式轮播背景图(基于 Vue 3 与 Element Plus)

文章归档于&#xff1a;https://www.yuque.com/u27599042/row3c6 组件库地址 npm&#xff1a;https://www.npmjs.com/package/xwb-ui?activeTabreadme小尾巴 UI 组件库源码 gitee&#xff1a;https://gitee.com/tongchaowei/xwb-ui小尾巴 UI 组件库测试代码 gitee&#xff1a…